Héritage en Python

02 Sep 2019 02 Sep 2019 26184 vues ESSADDOUKI Mostafa 9 min de lecture

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.

Définition — Héritage L'héritage modélise la relation "est un(e)" entre classes : un Employé est une Personne, un Chien est un Animal. Il permet la réutilisation du code en évitant la duplication et favorise une organisation hiérarchique des classes.
AvantageDescription
RéutilisationLe code de la classe mère est disponible sans réécriture
ExtensibilitéLa classe enfant ajoute ou spécialise le comportement
MaintenanceUne correction dans la mère se propage automatiquement
PolymorphismeLes objets enfants peuvent être utilisés là où la mère est attendue

Syntaxe — Héritage Python
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 existantes
Remarque — La classe object 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 — identique

Hé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éthodeSyntaxeRecommandation
super()super().__init__(nom, cin)✅ Recommandée (Python 3)
Appel directPersonne.__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}")
Sortie
=== Personne ===
Nom : Ali
CIN : AB123456

=== Employé ===
Nom : Ismail
CIN : EE4567
Salaire : 7000 DH

Employe(Ismail, salaire=7000)
Astuce — Réutiliser les méthodes du parent Dans une méthode redéfinie, on peut appeler la version parente avec super().methode(), au lieu de tout réécrire :
def afficher(self):
    super().afficher()      # affiche nom + cin
    print(f"Salaire : {self.salaire} DH")  # ajoute le salaire
Erreur — super().__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 GrandChild
Sortie
ISMAIL
32
Meknès
ISMAIL | 32 ans | Meknès
MRO — Method Resolution Order Quand Python cherche un attribut ou une méthode, il remonte la chaîne d'héritage dans un ordre précis appelé MRO(Method Resolution Order). Pour le connaître :
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.


Syntaxe — Héritage multiple Python
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__)
Sortie
Nom : Fatima | CIN : CD789012
Poste : Ingénieure | Salaire : 9500 DH
Employe(Fatima, Ingénieure)
(, , , )
Attention — Conflit de noms en héritage multipleSi deux classes mères définissent une méthode du même nom, c'est la première dans l'ordre du MRO qui est utilisée :
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 A

La 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éthodeRôleRedé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
Sortie
<__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__
Sortie
ISMAIL (CIN : EE456788)
Personne(nom='ISMAIL', cin='EE456788')
Astuce — __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()

Définition — isinstance() et issubclass()
  • isinstance(obj, Classe) — retourne True si obj est une instance de Classe ou d'une de ses sous-classes
  • issubclass(SousClasse, Classe) — retourne True si SousClasse est une sous-classe (directe ou indirecte) de Classe

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 inverse
Sortie
True
True
True
False
True
True
False
Astuce — Préférer 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)  # True

Récapitulatif

ConceptSyntaxe / OutilDescription
Héritage simpleclass E(P):E hérite d'une seule classe P
Héritage multi-niveauxclass C(B): … class G(C):Chaîne de classes dérivées
Héritage multipleclass E(A, B):E hérite de plusieurs classes
Appel parentsuper().__init__(…)Initialise les attributs hérités
MROClasse.__mro__Ordre de résolution des méthodes
Test d'instanceisinstance(obj, C)Vérifie le type avec héritage
Test sous-classeissubclass(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.