Apprenez en lisant dans l'ordre

L'héritage de classe — Réutiliser les fonctionnalités d'une classe existante

Apprends l'héritage de classe en Python. Hérite des attributs et méthodes avec class Enfant(Parent):, surcharge des méthodes, et appelle la version du parent avec super() — le tout avec des schémas.

La dernière fois on a utilisé des méthodes spéciales comme __add__ et __str__ pour apprendre des opérations natives à nos propres classes. Cette fois on couvre une des idées centrales de la POO : l'héritage de classe.

Pourquoi utiliser l'héritage ?

Quand tu construis des applis, tu tombes souvent sur des classes presque identiques mais qui diffèrent à quelques endroits. Imagine Customer, Employee et Admin — tous portent un name et un email et renvoient un greeting(), mais chacun a quelques attributs ou méthodes en plus.

Tu pourrais écrire les mêmes name / email / greeting() dans les trois classes — mais le code serait dupliqué et chaque modification devrait être faite à trois endroits. La solution propre est de mettre les parties partagées dans une classe parente et de faire en sorte que chaque classe enfant « hérite du parent et n'écrive que les différences ». C'est l'héritage.

Remonter le code partagé dans le parent
Person(parent)name / agegreeting()Employee(enfant)hérite
Les attributs et méthodes partagés vivent dans la classe parente (Person). Seules les différences vont dans l'enfant (Employee). Pas besoin de redéclarer name ou greeting à chaque fois.

Hériter d'un parent — class Enfant(Parent):

La syntaxe est simple : quand tu définis une sous-classe, mets la classe parente entre parenthèses après le nom de classe. La sous-classe récupère automatiquement tous les attributs et méthodes du parent.

Ci-dessous, Person est le parent (avec name, age et un greeting) et Employee est l'enfant. Employee ne définit pas une seule méthode propre, mais appeler greeting() dessus fonctionne grâce à l'héritage.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def greeting(self):
        print(f"Bonjour, {self.name}")

    def say_age(self):
        print(f"{self.age} ans")


class Employee(Person):       # hérite de Person
    pass                       # le corps peut être vide


e = Employee("Alice", 45)
e.greeting()                  # Bonjour, Alice   <- méthode du parent
e.say_age()                   # 45 ans
L'enfant obtient tout ce que le parent a
Person (parent)
  • Attributs : name / age
  • Méthodes : greeting() / say_age()
  • __init__(self, name, age)
Employee (enfant)
  • Le corps est vide (juste pass)
  • Hérite des attributs et méthodes du parent
  • Employee("Alice", 45) appelle le __init__ du parent
Même quand l'enfant est vide, tout ce que le parent possède est disponible. Réutiliser le comportement sans le réécrire est tout l'intérêt de l'héritage.

Construis un parent Person et un Employee qui ne fait que hériter.

① Définis class Person: avec __init__(self, name, age) qui assigne self.name et self.age.

② Dans Person, définis greeting(self) qui exécute print(f"Bonjour, {self.name}").

③ Écris class Employee(Person): avec juste pass pour le corps.

④ Construis e = Employee("Alice", 45) et appelle e.greeting().

(Une fois que ça tourne correctement, l'explication apparaîtra.)

Éditeur Python

Exécuter le code pour voir le résultat

La surcharge de méthode — Remplacer avec le même nom

L'héritage seul te donne le comportement du parent inchangé. Mais si tu écris une méthode avec le même nom dans la classe enfant, la version de l'enfant prend la priorité. C'est une surcharge (override).

Par exemple, pour donner à Employee un autre salut comme « Bonjour, Employé Alice », redéfinis greeting dans l'enfant. L'appeler sur une instance de Person donne le salut du parent ; l'appeler sur une instance de Employee donne celui de l'enfant. Le comportement bascule selon la classe à laquelle l'instance appelante appartient.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def greeting(self):
        print(f"Bonjour, {self.name}")


class Employee(Person):
    def greeting(self):                # même nom = surcharge
        print(f"Bonjour, Employé {self.name}")


p = Person("Léa", 30)
e = Employee("Alice", 45)
p.greeting()    # Bonjour, Léa
e.greeting()    # Bonjour, Employé Alice    <- la version de l'enfant gagne
Ordre de recherche des méthodes
e.greeting()greeting surEmployee?trouvée→ exécutegreeting surPerson?exécute si là,sinon erreur① chercheOuisi Non
Python cherche la méthode sur la classe enfant d'abord. Si elle n'y est pas, il remonte au parent. Même nom → l'enfant gagne — c'est la surcharge.

Ajoute une surcharge de greeting au code précédent.

① Construis la même classe Person qu'avant (__init__ et greeting).

② Définis class Employee(Person): et redéfinis-y greeting(self) pour exécuter print(f"Bonjour, Employé {self.name}").

③ Construis Person("Léa", 30) et Employee("Alice", 45), puis appelle greeting() sur chacun et compare.

Éditeur Python

Exécuter le code pour voir le résultat

super() — Appeler la méthode du parent

Parfois tu veux surcharger une méthode mais quand même t'appuyer sur le comportement du parent. C'est là que super() entre en jeu. Écrire super().method() appelle la méthode du même nom sur le parent de la classe actuelle.

Par exemple, suppose que tu veux « le greeting du parent (qui affiche Bonjour, Alice) suivi d'une ligne supplémentaire dans l'enfant ». Dans le greeting de l'enfant, appelle super().greeting() d'abord, puis ajoute ta propre ligne.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def greeting(self):
        print(f"Bonjour, {self.name}")


class Employee(Person):
    def greeting(self):
        super().greeting()                            # ① exécute d'abord le greeting du parent
        print(f"Je suis l'Employé {self.name}")       # ② puis la ligne propre à l'enfant


Employee("Alice", 45).greeting()
# Bonjour, Alice
# Je suis l'Employé Alice
super().greeting() réutilise la logique du parent
Employee.greeting()corps dugreeting enfantsuper().greeting()exécute legreeting parentreste ducorps enfantappeléexéc.
Dans le greeting de l'enfant, appeler super().greeting() exécute directement le greeting du parent. self est passé automatiquement — tu ne l'écris pas.

Surcharger __init__ pour ajouter des attributs

Là où super() brille le plus, c'est quand tu surcharges __init__. Imagine que la classe enfant a besoin des attributs du parent plus quelques uns à elle — par exemple, Employee doit aussi porter un phone_number.

Dans ce cas tu redéfinis __init__ dans l'enfant, mais l'initialisation du parent (self.name = name etc.) est gérée en une ligne par super().__init__(name, age), et tu ajoutes les attributs supplémentaires après. Comme ça tu n'as pas à répéter les assignations de name / age.

Le __init__ enfant construit attributs parent et enfant
Employee("Alice", 45, "06-12-...")__init__ enfantse lancesuper().__init__(name, age)le parent assignename / ageself.phone_number= phone_numberattrs parent + enfantprêtsappelé
Appeler Employee(...) exécute le __init__ de l'enfant → super().__init__(name, age) laisse le parent assigner name / age → puis l'enfant ajoute phone_number. État final : attributs parent + enfant tous en place.
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age


class Employee(Person):
    def __init__(self, name, age, phone_number):
        super().__init__(name, age)               # ① le parent définit name / age
        self.phone_number = phone_number           # ② ajoute l'attribut propre à l'enfant

    def show(self):
        print(f"{self.name} / {self.age} / {self.phone_number}")


Employee("Alice", 45, "06-12-34-56-78").show()
# Alice / 45 / 06-12-34-56-78

Oublie super().__init__(...) et les attributs disparaissent

Si tu surcharges __init__ mais que tu oublies d'appeler super().__init__(...), les assignations du parent comme self.name = name n'arrivent jamais. La prochaine fois que tu lis self.name, tu obtiens un AttributeError. Chaque fois que tu surcharges __init__ dans une classe enfant, appelle super().__init__(...) tout en haut — fais-en une habitude.

Ajoute un phone_number à Employee en surchargeant __init__.

① Définis class Person: avec __init__(self, name, age) qui assigne self.name et self.age.

② Définis class Employee(Person): avec __init__(self, name, age, phone_number). À l'intérieur, appelle d'abord super().__init__(name, age), puis self.phone_number = phone_number.

③ Dans Employee, définis show(self) qui exécute print(f"{self.name} / {self.age} / {self.phone_number}").

④ Construis Employee("Alice", 45, "06-12-34-56-78") et appelle show().

Éditeur Python

Exécuter le code pour voir le résultat
QUIZ

Vérification des connaissances

Répondez à chaque question une par une.

Question 1Laquelle des propositions suivantes est la bonne façon de faire que Dog hérite de Animal ?

Question 2Quelle est la description la plus précise de la surcharge de méthode ?

Question 3Si tu oublies d'appeler super().__init__(...) dans le __init__ d'un enfant, que se passe-t-il ?