L'héritage et le polymorphisme en Python

@joekakone

Joseph Konka @joekakone

03/03/2026 · 11 min

Maîtrisez l'héritage simple et multiple en Python : réutilisation de code, fonction super(), surcharge de méthodes, polymorphisme d'objets et ordre de résolution des méthodes (MRO).

L'héritage et le polymorphisme en Python#

L'héritage est l'un des piliers majeurs de la Programmation Orientée Objet. Il permet de définir une nouvelle classe (appelée classe fille, dérivée ou sous-classe) à partir d'une classe existante (classe mère, parente ou classe de base).

La classe fille hérite automatiquement de tous les attributs et de toutes les méthodes de sa classe mère, tout en ayant la possibilité : 1. D'ajouter de nouveaux attributs et comportements spécifiques. 2. De redéfinir (override) des méthodes existantes pour adapter leur logique métier.


1. Syntaxe de base et la fonction super()#

Pour faire hériter une classe d'une autre, on indique le nom de la classe parente entre parenthèses après le nom de la classe fille : class Enfant(Parent):.

Pour initialiser les attributs hérités sans dupliquer le code du constructeur parent, on utilise la fonction native super() :

classDiagram
    class Personne {
        +str nom
        +str email
        +se_presenter()
    }
    class Etudiant {
        +str filiere
        +float moyenne
        +se_presenter()
    }
    class Enseignant {
        +str matiere
        +float salaire
        +se_presenter()
    }
    Personne <|-- Etudiant
    Personne <|-- Enseignant
class Personne:
    """Classe de base représentant un individu."""

    def __init__(self, nom: str, email: str):
        self.nom = nom
        self.email = email

    def se_presenter(self) -> str:
        return f"Bonjour, je m'appelle {self.nom} (Contact : {self.email})."


class Etudiant(Personne):
    """Classe fille spécialisant Personne pour le milieu académique."""

    def __init__(self, nom: str, email: str, filiere: str, moyenne: float):
        # 1. Appel du constructeur de la classe mère Personne
        super().__init__(nom, email)

        # 2. Attributs spécifiques à l'étudiant
        self.filiere = filiere
        self.moyenne = moyenne

    # Redéfinition (Override) de la méthode se_presenter
    def se_presenter(self) -> str:
        intro_parent = super().se_presenter()
        return f"{intro_parent} Je suis etudiant en {self.filiere} avec une moyenne de {self.moyenne:.1f}/20."


# Utilisation :
e = Etudiant("Alice Dubois", "alice@algojungle.com", "Data Science", 16.5)
print(e.se_presenter())

2. Le Polymorphisme en action#

Le polymorphisme (plusieurs formes) est la capacité de traiter des objets de classes différentes de manière uniforme à travers une interface partagée :

class FormeGeometrique:
    def calculer_aire(self) -> float:
        raise NotImplementedError("Les classes filles doivent implementer cette methode !")

class Rectangle(FormeGeometrique):
    def __init__(self, longueur: float, largeur: float):
        self.longueur = longueur
        self.largeur = largeur

    def calculer_aire(self) -> float:
        return self.longueur * self.largeur

class Disque(FormeGeometrique):
    def __init__(self, rayon: float):
        self.rayon = rayon

    def calculer_aire(self) -> float:
        import math
        return math.pi * (self.rayon ** 2)

# Liste hétérogène de formes géométriques
formes: list[FormeGeometrique] = [
    Rectangle(10.0, 5.0),
    Disque(4.0),
    Rectangle(3.0, 8.0)
]

# Traitement polymorphique : le même appel '.calculer_aire()' s'adapte à chaque objet !
for index, f in enumerate(formes, start=1):
    print(f"Forme #{index} ({f.__class__.__name__:<10}) -> Aire = {f.calculer_aire():>6.2f} m2")

3. Vérification des relations d'héritage#

Python propose deux fonctions pour inspecter la hiérarchie des types : - isinstance(objet, Classe) : teste si un objet est une instance de la classe ou de l'une de ses sous-classes. - issubclass(ClasseFille, ClasseMere) : teste si une classe hérite d'une autre.

rect = Rectangle(4, 5)

print(isinstance(rect, Rectangle))         # True
print(isinstance(rect, FormeGeometrique))  # True (car Rectangle hérite de FormeGeometrique)
print(isinstance(rect, object))            # True (toutes les classes dérivent de object !)

print(issubclass(Rectangle, FormeGeometrique))  # True
print(issubclass(Rectangle, Disque))           # False

4. L'héritage multiple et l'ordre MRO (Method Resolution Order)#

Contrairement à Java ou C#, Python autorise une classe fille à hériter de plusieurs classes mères simultanément (class C(A, B):).

Pour savoir quelle méthode exécuter en cas de conflit de noms (le fameux problème du losange ou Diamond Problem), Python utilise un algorithme rigoureux appelé C3 Linearization pour établir le MRO (Method Resolution Order) :

class Connectable:
    def initialiser(self):
        print("Initialisation reseau.")

class Journalisable:
    def initialiser(self):
        print("Initialisation du journal de logs.")

# Héritage multiple : Connectable est listé en premier
class ServeurAPI(Connectable, Journalisable):
    pass

s = ServeurAPI()
s.initialiser()  # Affiche "Initialisation reseau." car Connectable a la priorité !

# Consulter l'ordre exact de recherche MRO :
print("MRO :", [cls.__name__ for cls in ServeurAPI.mro()])
# ['ServeurAPI', 'Connectable', 'Journalisable', 'object']

5. Mise en pratique : Système de gestion des collaborateurs d'entreprise#

Concevons une hiérarchie d'entreprise complète avec calcul différencié des primes de fin d'année :

class Collaborateur:
    """Classe de base pour tout employé."""

    def __init__(self, matricule: str, nom: str, salaire_mensuel: float):
        self.matricule = matricule
        self.nom = nom
        self.salaire_mensuel = salaire_mensuel

    def calculer_prime_annuelle(self) -> float:
        """Prime standard équivalente à 50% d'un salaire mensuel."""
        return self.salaire_mensuel * 0.50

    def generer_fiche_paie(self) -> None:
        prime = self.calculer_prime_annuelle()
        total_annuel = (self.salaire_mensuel * 12) + prime
        print(f"[{self.matricule}] {self.nom:<18} ({self.__class__.__name__:<12}) "
              f"| Salaire: {self.salaire_mensuel:>7.2f} EUR | Prime: {prime:>7.2f} EUR | Total: {total_annuel:>8.2f} EUR")


class Developpeur(Collaborateur):
    def __init__(self, matricule: str, nom: str, salaire: float, langage: str):
        super().__init__(matricule, nom, salaire)
        self.langage = langage

    def calculer_prime_annuelle(self) -> float:
        # Prime bonifiée de 75% du salaire mensuel
        return self.salaire_mensuel * 0.75


class Manager(Collaborateur):
    def __init__(self, matricule: str, nom: str, salaire: float, taille_equipe: int):
        super().__init__(matricule, nom, salaire)
        self.taille_equipe = taille_equipe

    def calculer_prime_annuelle(self) -> float:
        # 1 mois de salaire + 150 EUR par collaborateur managé
        return self.salaire_mensuel + (self.taille_equipe * 150.0)


# Démonstration du système :
equipe = [
    Developpeur("DEV-01", "Koffi Mensah", 3800.0, "Python"),
    Developpeur("DEV-02", "Sara Gomez", 4200.0, "React/Node"),
    Manager("MGR-01", "Alexandre Martin", 5500.0, taille_equipe=6),
    Collaborateur("RH-01", "Fatou Ndiaye", 3100.0)
]

print("=== BILAN DE REMUNERATION ANNUELLE (ALGOJUNGLE RH) ===")
for employe in equipe:
    employe.generer_fiche_paie()

6. Défi d'application#

À partir de la classe CompteBancaire vue dans le chapitre précédent, créez une sous-classe CompteEpargne qui hérite de CompteBancaire et ajoute un attribut taux_interet (ex: 0.03 pour 3%). Implémentez une méthode verser_interets() qui calcule les intérêts générés et les crédite directement sur le solde du compte.

Commentaires

Inscrivez-vous à une formation complète

Voir le catalogue