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_interetcompte = 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 = plafondsuper() 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__prive10.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 + 32t = Temperature(25)
t.celsius = 30 # setter
print(t.fahrenheit) # 86.010.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éfautGénère automatiquement __init__, __repr__, __eq__, __hash__.
Options :
@dataclass(frozen=True, order=True)
class Point:
x: float
y: float10.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