🐍 Python : Programmation Orientée Objet

La programmation orientée objet (POO) en Python permet de structurer le code en regroupant données et comportements dans des objets. Cette fiche vous guide à travers les bases de la POO : classes, objets, constructeurs, héritage, encapsulation, et bien plus.

📑 Sommaire

🏗️ Définir une classe

Une classe est un modèle (ou "plan") qui définit des attributs et des méthodes :

class Chien:
    # Attribut de classe (partagé par toutes les instances)
    espece = "Canis familiaris"
    
    # Méthode d'instance
    def aboyer(self):
        print("Ouaf !")
        
    def se_presenter(self):
        print(f"Je suis un {self.espece}")

🔨 Instancier un objet

Un objet est une instance d'une classe, créée en appelant la classe comme une fonction :

# Création d'une instance
medor = Chien()

# Appel de méthodes
medor.aboyer()        # Affiche : Ouaf !
medor.se_presenter()  # Affiche : Je suis un Canis familiaris

# Ajout d'attributs d'instance
medor.nom = "Médor"
medor.age = 3
print(f"{medor.nom} a {medor.age} ans")

🧱 Constructeur (__init__)

La méthode __init__ est appelée lors de la création d'une instance et permet d'initialiser ses attributs :

class Chien:
    def __init__(self, nom, age=1):
        self.nom = nom
        self.age = age
        print(f"Un nouveau chien nommé {nom} a été créé !")
    
    def info(self):
        return f"{self.nom} a {self.age} ans"

# Utilisation du constructeur avec arguments
medor = Chien("Médor", 3)
rex = Chien("Rex")  # Utilise la valeur par défaut pour age

print(medor.info())  # Affiche : Médor a 3 ans
print(rex.info())    # Affiche : Rex a 1 an

📐 Héritage

L'héritage permet à une classe de recevoir les attributs et méthodes d'une autre classe :

class Animal:
    def __init__(self, nom):
        self.nom = nom
    
    def parler(self):
        print("Je suis un animal")

class Chat(Animal):  # Chat hérite d'Animal
    def parler(self):  # Redéfinition de la méthode
        print("Miaou !")
    
    def ronronner(self):  # Nouvelle méthode
        print("Ronron...")

# Utilisation
felix = Chat("Félix")
felix.parler()     # Affiche : Miaou !
felix.ronronner()  # Affiche : Ronron...
print(felix.nom)   # Affiche : Félix (hérité d'Animal)

Appel à la méthode parente avec super() :

class Chien(Animal):
    def __init__(self, nom, race):
        super().__init__(nom)  # Appelle le constructeur d'Animal
        self.race = race
    
    def parler(self):
        super().parler()  # Appelle la méthode parler d'Animal
        print("Ouaf !")

rex = Chien("Rex", "Berger allemand")
rex.parler()  # Affiche : Je suis un animal
              #          Ouaf !

🔒 Encapsulation

L'encapsulation permet de restreindre l'accès aux attributs et méthodes d'une classe :

class Compte:
    def __init__(self, proprietaire, solde_initial=0):
        self.proprietaire = proprietaire  # Public
        self.__solde = solde_initial      # Privé (notation avec double underscore)
    
    def consulter_solde(self):
        return f"Solde actuel : {self.__solde}€"
    
    def deposer(self, montant):
        if montant > 0:
            self.__solde += montant
            return True
        return False
    
    def retirer(self, montant):
        if 0 < montant <= self.__solde:
            self.__solde -= montant
            return True
        return False

# Utilisation
compte = Compte("Guillaume", 1000)
print(compte.consulter_solde())  # Affiche : Solde actuel : 1000€

compte.deposer(500)
print(compte.consulter_solde())  # Affiche : Solde actuel : 1500€

# Tentative d'accès direct à l'attribut privé
# print(compte.__solde)  # Génère une erreur AttributeError

# Python permet tout de même d'y accéder avec une notation spéciale (à éviter)
print(compte._Compte__solde)  # Affiche : 1500

🔄 Méthodes spéciales

Python offre des méthodes spéciales (commençant et finissant par double underscore) pour personnaliser le comportement des objets :

class Vecteur:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    # Représentation pour str()
    def __str__(self):
        return f"Vecteur({self.x}, {self.y})"
    
    # Représentation pour repr()
    def __repr__(self):
        return f"Vecteur({self.x}, {self.y})"
    
    # Addition de vecteurs
    def __add__(self, autre):
        return Vecteur(self.x + autre.x, self.y + autre.y)
    
    # Comparaison d'égalité
    def __eq__(self, autre):
        return self.x == autre.x and self.y == autre.y
    
    # Obtenir la longueur du vecteur avec len()
    def __len__(self):
        import math
        return math.floor(math.sqrt(self.x**2 + self.y**2))

# Utilisation
v1 = Vecteur(3, 4)
v2 = Vecteur(1, 1)

print(v1)          # Affiche : Vecteur(3, 4)
print(v1 + v2)     # Affiche : Vecteur(4, 5)
print(v1 == v2)    # Affiche : False
print(len(v1))     # Affiche : 5
🎁 Bonus : Techniques avancées

Méthodes de classe et méthodes statiques

class MaClasse:
    compteur = 0  # Variable de classe
    
    def __init__(self):
        MaClasse.compteur += 1
    
    # Méthode de classe (accès aux attributs de classe)
    @classmethod
    def get_compteur(cls):
        return f"Nombre d'instances : {cls.compteur}"
    
    # Méthode statique (indépendante de la classe)
    @staticmethod
    def info():
        return "Cette classe est un exemple."

# Utilisation
obj1 = MaClasse()
obj2 = MaClasse()

print(MaClasse.get_compteur())  # Affiche : Nombre d'instances : 2
print(MaClasse.info())          # Affiche : Cette classe est un exemple.

Propriétés (@property)

class Personne:
    def __init__(self, nom, age):
        self._nom = nom
        self._age = age
    
    # Getter pour age
    @property
    def age(self):
        return self._age
    
    # Setter pour age
    @age.setter
    def age(self, valeur):
        if 0 <= valeur <= 150:
            self._age = valeur
        else:
            raise ValueError("Age invalide")
    
    # Getter pour nom
    @property
    def nom(self):
        return self._nom.title()

# Utilisation
p = Personne("jean", 30)
print(p.nom)    # Affiche : Jean (avec majuscule)
print(p.age)    # Affiche : 30

p.age = 31      # Utilise le setter
print(p.age)    # Affiche : 31

# p.age = 200   # Génère une erreur ValueError
🏠 Retour au sommaire général