10. Programmation Orientée Objet

class, héritage, @property, dunder methods, dataclasses, @staticmethod, @classmethod.


10.1 Définition d’une classe

class CompteBancaire:
    """Exemple de classe."""
 
    taux_interet = 0.02  # attribut de classe (partagé)
 
    def __init__(self, titulaire: str, solde: float = 0):
        self.titulaire = titulaire   # attribut d'instance
        self.solde = solde
 
    def deposer(self, montant: float):
        self.solde += montant
 
    def retirer(self, montant: float):
        if montant > self.solde:
            raise ValueError("Solde insuffisant")
        self.solde -= montant
 
    def appliquer_interets(self):
        self.solde *= 1 + self.taux_interet
compte = CompteBancaire("Alice", 1000)
compte.deposer(500)
compte.retirer(200)
compte.appliquer_interets()
print(compte.solde)

10.2 Héritage

class CompteEpargne(CompteBancaire):
    taux_interet = 0.04  # surcharge
 
    def __init__(self, titulaire: str, solde: float = 0, plafond: float = 10000):
        super().__init__(titulaire, solde)  # appel au parent
        self.plafond = plafond

super() résout l’ordre MRO (Method Resolution Order).

10.3 Visibilité

Python n’a pas de private réel. Convention :

class Exemple:
    def __init__(self):
        self.public = 1
        self._protege = 2    # convention : usage interne
        self.__prive = 3     # name mangling : _Exemple__prive

10.4 @property

Contrôle d’accès sans getters/setters explicites :

class Temperature:
    def __init__(self, celsius: float):
        self._celsius = celsius
 
    @property
    def celsius(self) -> float:
        return self._celsius
 
    @celsius.setter
    def celsius(self, valeur: float):
        if valeur < -273.15:
            raise ValueError("En dessous du zéro absolu")
        self._celsius = valeur
 
    @property
    def fahrenheit(self) -> float:
        return self._celsius * 9/5 + 32
t = Temperature(25)
t.celsius = 30          # setter
print(t.fahrenheit)     # 86.0

10.5 @staticmethod et @classmethod

class Utilitaires:
    @staticmethod
    def helper(x: int) -> int:
        """Pas d'accès à self ou cls."""
        return x ** 2
 
    @classmethod
    def depuis_chaine(cls, chaine: str):
        """Constructeur alternatif."""
        return cls(int(chaine))

10.6 Dunder methods (magic methods)

Opérateurs et comportements :

class Vecteur:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y
 
    def __repr__(self) -> str:
        return f"Vecteur({self.x}, {self.y})"
 
    def __str__(self) -> str:
        return f"({self.x}, {self.y})"
 
    def __add__(self, other):
        return Vecteur(self.x + other.x, self.y + other.y)
 
    def __mul__(self, scalaire: float):
        return Vecteur(self.x * scalaire, self.y * scalaire)
 
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
 
    def __len__(self) -> int:
        return int((self.x**2 + self.y**2)**0.5)

Autres : __getitem__, __setitem__, __call__, __enter__/__exit__, __iter__, __hash__.

10.7 dataclasses (PEP 557)

Raccourci pour classes de données :

from dataclasses import dataclass
 
@dataclass
class Point:
    x: float
    y: float
    z: float = 0.0  # valeur par défaut

Génère automatiquement __init__, __repr__, __eq__, __hash__.

Options :

@dataclass(frozen=True, order=True)
class Point:
    x: float
    y: float

10.8 __slots__

Réduit la mémoire en fixant les attributs :

class Point:
    __slots__ = ("x", "y")  # pas de __dict__
 
    def __init__(self, x, y):
        self.x = x
        self.y = y

🔗 ← Retour au cours · ← précédent · Suivant →