Leçons du module (2/4)
Héritage
L'héritage (inheritance) permet de créer une nouvelle classe (la subclass ou sous-classe) qui hérite des attributs et méthodes d'une classe existante (la base class ou classe de base), et peut les étendre ou les remplacer (override).
Syntaxe de base
class Animale:
def __init__(self, nome):
self.nome = nome
def saluta(self):
return f"{self.nome} fa un verso"
class Cane(Animale): # Cane HÉRITE de Animale
def saluta(self): # OVERRIDE du méthode (redéfinition)
return f"{self.nome} dice WOOF!"
a = Animale("X")
c = Cane("Fido")
a.saluta() # 'X fa un verso'
c.saluta() # 'Fido dice WOOF!'Cane hérite de __init__ d'Animale sans avoir besoin de le réécrire.
super() : appeler la méthode de base
Lorsque vous souhaitez étendre une méthode de base (et non la remplacer complètement), utilisez
super() :
class Animale:
def __init__(self, nome):
self.nome = nome
class Cane(Animale):
def __init__(self, nome, razza):
super().__init__(nome) # délègue à la base
self.razza = razza
c = Cane("Fido", "Labrador")
c.nome # 'Fido'
c.razza # 'Labrador'isinstance : vérification du type
isinstance(c, Cane) # True
isinstance(c, Animale) # True (la base aussi)
isinstance(c, str) # Falseisinstance(x, BaseClass) reconnaît également toutes les sous-classes : c'est ce qui rend
l'héritage utile pour le polymorphisme.
animali = [Cane("Fido", "X"), Animale("Pippo")]
for a in animali:
print(a.saluta()) # chaque objet répond à sa manièreMRO (Method Resolution Order) — aperçu
En cas d'héritage multiple, Python décide dans quel ordre chercher une méthode en suivant le MRO, calculé avec l'algorithme C3. Dans 95 % des cas, il suffit de savoir :
- il cherche d'abord dans l'instance,
- puis dans sa classe,
- puis dans les classes de base dans l'ordre de leur déclaration.
Cane.__mro__
# (<class 'Cane'>, <class 'Animale'>, <class 'object'>)object est la racine de toutes les classes en Python 3.
À vous de jouer
Étant donné `class Vehicle: def __init__(self, brand): self.brand = brand`, définissez `Car(Vehicle)` avec __init__(self, brand, model) qui appelle super().__init__ et stocke self.model. Créez `a = Car('Fiat', '500')` et évaluez `(a.brand, a.model)`.
Afficher l'indice
super().__init__(brand) puis self.model = model.
Solution disponible après 3 tentatives
Exercice de révision
Définissez `class Shape: def area(self): return 0` et `class Square(Shape)` avec __init__(self, side) et area() qui renvoie side * side. Créez `q = Square(5)` et évaluez le tuple `(q.area(), isinstance(q, Shape))`.
Afficher l'indice
self.side * self.side.
Solution disponible après 3 tentatives
Défi supplémentaire
Créez une classe `Square` qui hérite de la classe `Rectangle` (définie ci-dessous). Le constructeur de `Square` doit prendre un paramètre unique `side` et le passer à `super().__init__(side, side)`. Instanciez un carré avec un côté de `6` dans `sq` et évaluez `sq.area()`.
Afficher l'indice
Déclarez class Square(Rectangle): et appelez super().__init__(side, side) dans le constructeur.
Solution disponible après 3 tentatives