Question 1Laquelle des propositions suivantes est la bonne façon de faire que Dog hérite de Animal ?
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.
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
- Attributs : name / age
- Méthodes : greeting() / say_age()
- __init__(self, name, age)
- Le corps est vide (juste pass)
- → Hérite des attributs et méthodes du parent
- Employee("Alice", 45) appelle le __init__ du parent
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
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
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.
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.
Vérification des connaissances
Répondez à chaque question une par une.
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 ?