Module : L'Héritage
1. Quoi : L'Héritage
L'héritage est l'un des piliers de la programmation orientée objet. C'est un mécanisme qui permet de créer une nouvelle classe (appelée classe enfant, sous-classe ou classe dérivée) à partir d'une classe existante (appelée classe parente, super-classe ou classe de base).
La classe enfant hérite de tous les attributs et de toutes les méthodes de la classe parente. Elle peut ensuite :
- Utiliser les fonctionnalités héritées telles quelles.
- Ajouter de nouveaux attributs et de nouvelles méthodes.
- Redéfinir (ou "surcharger", override) des méthodes de la classe parente pour qu'elles aient un comportement spécifique.
2. Pourquoi : Réutilisation et Spécialisation
- Réutilisation du code (Principe DRY) : Au lieu de copier-coller du code entre des classes similaires, vous placez le code commun dans une classe parente et vous en faites hériter les classes enfants.
- Création de hiérarchies logiques : L'héritage permet de modéliser des relations "est un" (a is-a relationship). Par exemple, un
Chienest unAnimal. UneVoitureElectriqueest uneVoiture. - Spécialisation : Vous partez d'une classe générale et vous créez des versions plus spécifiques qui ajoutent ou modifient des fonctionnalités.
3. Comment : La Syntaxe en Python
A. Créer une classe enfant
Pour faire hériter une classe, on indique le nom de la classe parente entre parenthèses lors de la définition de la classe enfant.
# Classe Parente
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
# Comportement générique
print(f"{self.name} makes a sound.")
# Classe Enfant qui hérite de Animal
class Dog(Animal):
# Pour l'instant, Dog ne fait rien de plus que Animal
pass
# Utilisation
generic_animal = Animal("Creature")
generic_animal.speak() # Creature makes a sound.
my_dog = Dog("Buddy") # Dog hérite du __init__ de Animal
my_dog.speak() # Dog hérite de la méthode speak() -> Buddy makes a sound.
B. Redéfinir une méthode de la classe parente
La classe enfant peut fournir sa propre implémentation d'une méthode qui existe déjà dans la classe parente.
class Cat(Animal):
# On redéfinit la méthode speak() pour la classe Cat
def speak(self):
print(f"{self.name} says: Meow!")
my_cat = Cat("Whiskers")
my_cat.speak() # Affiche "Whiskers says: Meow!" et non le message générique.
C. Ajouter de nouvelles méthodes
La classe enfant peut avoir ses propres méthodes, qui n'existent pas dans la classe parente.
class Dog(Animal):
# Redéfinition
def speak(self):
print(f"{self.name} says: Woof!")
# Nouvelle méthode, spécifique à Dog
def fetch(self, item):
print(f"{self.name} fetches the {item}.")
my_dog = Dog("Rex")
my_dog.speak() # Rex says: Woof!
my_dog.fetch("ball") # Rex fetches the ball.
D. Étendre le constructeur __init__
Souvent, la classe enfant a besoin d'ajouter ses propres attributs en plus de ceux de la classe parente. Pour cela, il faut :
- Redéfinir la méthode
__init__dans la classe enfant. - Appeler explicitement le constructeur de la classe parente pour s'assurer que ses attributs sont bien initialisés. On utilise pour cela
super().__init__().
class ElectricCar(Car): # On suppose qu'on a une classe Car
"""Represents aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year, battery_size):
"""
Initialize attributes of the parent class.
Then initialize attributes specific to an electric car.
"""
# 1. Appelle le __init__ de la classe parente (Car)
super().__init__(make, model, year)
# 2. Ajoute le nouvel attribut spécifique à ElectricCar
self.battery_size = battery_size # en kWh
# Nouvelle méthode
def describe_battery(self):
"""Print a statement describing the battery size."""
print(f"This car has a {self.battery_size}-kWh battery.")
# Redéfinition d'une méthode existante (si Car avait une méthode fill_gas_tank)
def fill_gas_tank(self):
"""Electric cars don't have gas tanks."""
print("This car doesn't need a gas tank!")
# Utilisation
my_tesla = ElectricCar('tesla', 'model s', 2023, 100)
print(my_tesla.get_descriptive_name()) # Méthode héritée de Car
my_tesla.describe_battery() # Nouvelle méthode
super()est une fonction spéciale qui vous permet d'appeler des méthodes de la classe parente, évitant ainsi d'avoir à la nommer explicitement. C'est la manière moderne et recommandée de le faire.
4. Héritage Multiple
Python autorise une classe à hériter de plusieurs classes parentes.
class A:
def method_a(self):
print("Method from A")
class B:
def method_b(self):
print("Method from B")
class C(A, B): # Hérite de A et de B
pass
instance_c = C()
instance_c.method_a() # Method from A
instance_c.method_b() # Method from B
L'héritage multiple peut être puissant, mais il peut aussi introduire de la complexité, notamment le "problème du diamant" (diamond problem), qui concerne l'ordre dans lequel les méthodes sont résolues (MRO - Method Resolution Order). Il doit être utilisé avec prudence.