L'héritage en Python
L'héritage est un mécanisme fondamental de la POO qui permet de créer une nouvelle classe — la classe enfant — basée sur une classe existante — la classe mère. La classe enfant hérite automatiquement de tous les attributs et méthodes de la classe mère, et peut en ajouter de nouveaux ou en redéfinir.
| Avantage | Description |
|---|---|
| Réutilisation | Le code de la classe mère est disponible sans réécriture |
| Extensibilité | La classe enfant ajoute ou spécialise le comportement |
| Maintenance | Une correction dans la mère se propage automatiquement |
| Polymorphisme | Les objets enfants peuvent être utilisés là où la mère est attendue |
class Mere:
# attributs et méthodes de la classe mère
class Enfant(Mere):
# hérite de Mere
# peut ajouter de nouveaux attributs/méthodes
# peut redéfinir (surcharger) des méthodes existantesobject En Python 3, toute classe hérite implicitement de object, la racine de la hiérarchie. Les deux déclarations suivantes sont strictement équivalentes :class Personne: pass # implicite
class Personne(object): pass # explicite — identiqueHéritage simple
L'héritage simple désigne le cas où une classe enfant hérite d'une seule classe mère. C'est la forme la plus courante et la plus lisible d'héritage.
Appel du constructeur parent — super()
Lorsque la classe enfant définit son propre __init__, elle doit explicitement appeler le constructeur de la classe mère pour initialiser les attributs hérités. Python fournit super() pour cela.
| Méthode | Syntaxe | Recommandation |
|---|---|---|
super() | super().__init__(nom, cin) | ✅ Recommandée (Python 3) |
| Appel direct | Personne.__init__(self, nom, cin) | ⚠️ Fonctionne mais fragile en héritage multiple |
Exemple n°1 — Classe Personne et Employe
class Personne:
def __init__(self, nom, cin):
self.nom = nom
self.cin = cin
def afficher(self):
print(f"Nom : {self.nom}")
print(f"CIN : {self.cin}")
def __str__(self):
return f"Personne({self.nom}, {self.cin})"
class Employe(Personne):
def __init__(self, nom, cin, salaire):
super().__init__(nom, cin) # ✅ initialise nom et cin
self.salaire = salaire
def afficher(self):
super().afficher() # réutilise l'affichage parent
print(f"Salaire : {self.salaire} DH")
def __str__(self):
return f"Employe({self.nom}, salaire={self.salaire})"
# Test
p = Personne("Ali", "AB123456")
e = Employe("Ismail", "EE4567", 7000)
print("=== Personne ===")
p.afficher()
print("\n=== Employé ===")
e.afficher()
print(f"\n{e}")=== Personne === Nom : Ali CIN : AB123456 === Employé === Nom : Ismail CIN : EE4567 Salaire : 7000 DH Employe(Ismail, salaire=7000)
super().methode(), au lieu de tout réécrire :def afficher(self):
super().afficher() # affiche nom + cin
print(f"Salaire : {self.salaire} DH") # ajoute le salairesuper().__init__(self, nom, cin) Ne pas passer self à super().__init__(). super()le gère automatiquement :# ❌ TypeError : trop d'arguments
super().__init__(self, nom, cin)
# ✅ Correct
super().__init__(nom, cin)Héritage multi-niveaux
Python supporte l'héritage en chaîne : une classe enfant peut elle-même être la mère d'une autre classe, formant une hiérarchie à plusieurs niveaux.
Exemple n°2 — Hiérarchie Base → Child → GrandChild
class Base:
def __init__(self, nom):
self.nom = nom
def getNom(self):
return self.nom
class Child(Base):
def __init__(self, nom, age):
super().__init__(nom)
self.age = age
def getAge(self):
return self.age
class GrandChild(Child):
def __init__(self, nom, age, adresse):
super().__init__(nom, age)
self.adresse = adresse
def getAdresse(self):
return self.adresse
def __str__(self):
return f"{self.nom} | {self.age} ans | {self.adresse}"
# Test
g = GrandChild("ISMAIL", 32, "Meknès")
print(g.getNom()) # hérité de Base
print(g.getAge()) # hérité de Child
print(g.getAdresse()) # défini dans GrandChild
print(g) # __str__ de GrandChildISMAIL 32 Meknès ISMAIL | 32 ans | Meknès
print(GrandChild.__mro__)
# (, , , )La recherche suit cet ordre : si la méthode n'est pas trouvée dans GrandChild, Python remonte vers Child, puis Base, puis object.Héritage multiple
Python permet à une classe d'hériter de plusieurs classes mères simultanément.
class Mere1:
# corps de Mere1
class Mere2:
# corps de Mere2
class Enfant(Mere1, Mere2):
# hérite de Mere1 ET Mere2
# l'ordre détermine la priorité (MRO)Exemple n°3 — Héritage multiple avec mixins
class Identite:
def __init__(self, nom, cin):
self.nom = nom
self.cin = cin
def afficher_identite(self):
print(f"Nom : {self.nom} | CIN : {self.cin}")
class Contrat:
def __init__(self, salaire, poste):
self.salaire = salaire
self.poste = poste
def afficher_contrat(self):
print(f"Poste : {self.poste} | Salaire : {self.salaire} DH")
class Employe(Identite, Contrat):
def __init__(self, nom, cin, salaire, poste):
Identite.__init__(self, nom, cin)
Contrat.__init__(self, salaire, poste)
def afficher(self):
self.afficher_identite()
self.afficher_contrat()
def __str__(self):
return f"Employe({self.nom}, {self.poste})"
# Test
e = Employe("Fatima", "CD789012", 9500, "Ingénieure")
e.afficher()
print(e)
print(Employe.__mro__)Nom : Fatima | CIN : CD789012 Poste : Ingénieure | Salaire : 9500 DH Employe(Fatima, Ingénieure) (, , , )
class A:
def bonjour(self): print("Bonjour depuis A")
class B:
def bonjour(self): print("Bonjour depuis B")
class C(A, B): pass # A est en premier → A.bonjour() utilisée
C().bonjour() # → Bonjour depuis ALa classe de base object
Toute classe Python hérite implicitement de object. Cette classe racine fournit des méthodes spéciales (dunder methods) disponibles dans toutes les classes.
| Méthode | Rôle | Redéfinir ? |
|---|---|---|
__new__(cls) | Crée l'instance (alloue la mémoire) | ⚠️ Rarement nécessaire |
__init__(self) | Initialise les attributs de l'instance | ✅ Très souvent |
__str__(self) | Représentation lisible — utilisée par print() | ✅ Recommandé |
__repr__(self) | Représentation technique — utilisée par le débogueur | ✅ Recommandé |
__eq__(self, other) | Opérateur == entre objets | ✅ Si nécessaire |
Exemple n°4 — Sans __str__ : affichage par défaut
class Personne:
def __init__(self, nom, cin):
self.nom = nom
self.cin = cin
p = Personne("ISMAIL", "EE456788")
print(p) # affichage par défaut de object<__main__.Personne object at 0x10c287358>
Exemple n°5 — Avec __str__ et __repr__
class Personne:
def __init__(self, nom, cin):
self.nom = nom
self.cin = cin
def __str__(self):
# Utilisé par print() — lisible pour l'utilisateur
return f"{self.nom} (CIN : {self.cin})"
def __repr__(self):
# Utilisé par le débogueur — utile pour le développeur
return f"Personne(nom='{self.nom}', cin='{self.cin}')"
p = Personne("ISMAIL", "EE456788")
print(p) # appelle __str__
print(repr(p)) # appelle __repr__ISMAIL (CIN : EE456788) Personne(nom='ISMAIL', cin='EE456788')
__str__ vs __repr__ __str__ est destiné à l'utilisateur final (lisible), __repr__ au développeur (précis et non ambigu). Si seul __repr__ est défini, print() l'utilisera à la place de __str__.Fonctions isinstance() et issubclass()
isinstance(obj, Classe)— retourneTruesiobjest une instance deClasseou d'une de ses sous-classesissubclass(SousClasse, Classe)— retourneTruesiSousClasseest une sous-classe (directe ou indirecte) deClasse
Exemple n°6 — Tests d'héritage
class Personne:
def __init__(self, nom, cin):
self.nom = nom
self.cin = cin
class Employe(Personne):
def __init__(self, nom, cin, salaire):
super().__init__(nom, cin)
self.salaire = salaire
p = Personne("Ali", "AB123")
e = Employe("Ismail", "EE4567", 7000)
# isinstance — tests sur e
print(isinstance(e, Employe)) # True — e est un Employe
print(isinstance(e, Personne)) # True — Employe hérite de Personne
print(isinstance(e, object)) # True — tout hérite de object
print(isinstance(p, Employe)) # False — p est Personne, pas Employe
# issubclass — tests sur les classes
print(issubclass(Employe, Personne)) # True
print(issubclass(Employe, object)) # True
print(issubclass(Personne, Employe)) # False — relation inverseTrue True True False True True False
isinstance() à type() Pour tester le type d'un objet, isinstance() est toujours préférable à type(obj) == Classecar il prend en compte l'héritage :e = Employe("X", "Y", 5000)
# ❌ Ne reconnaît pas l'héritage
type(e) == Personne # False — même si Employe hérite de Personne
# ✅ Prend en compte l'héritage
isinstance(e, Personne) # TrueRécapitulatif
| Concept | Syntaxe / Outil | Description |
|---|---|---|
| Héritage simple | class E(P): | E hérite d'une seule classe P |
| Héritage multi-niveaux | class C(B): … class G(C): | Chaîne de classes dérivées |
| Héritage multiple | class E(A, B): | E hérite de plusieurs classes |
| Appel parent | super().__init__(…) | Initialise les attributs hérités |
| MRO | Classe.__mro__ | Ordre de résolution des méthodes |
| Test d'instance | isinstance(obj, C) | Vérifie le type avec héritage |
| Test sous-classe | issubclass(A, B) | Vérifie la relation de dérivation |
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.