Introduction
L’héritage et le polymorphisme sont deux concepts fondamentaux de la programmation orientée objet (POO). En Python, l’héritage permet de créer de nouvelles classes basées sur des classes existantes, facilitant la réutilisation et l'extension du code. Le polymorphisme, quant à lui, permet à une classe dérivée de redéfinir les méthodes de la classe parent, offrant ainsi un comportement différent tout en gardant la même interface.
Dans cet article, nous explorerons comment l’héritage et le polymorphisme fonctionnent en Python, et comment ils vous permettent de concevoir des programmes modulaires, extensibles, et faciles à maintenir.
1. Qu'est-ce que l'héritage en Python ?
L'héritage est un mécanisme permettant de créer une nouvelle classe (appelée classe enfant ou classe dérivée) en se basant sur une classe existante (appelée classe parent). La classe enfant hérite des attributs et méthodes de la classe parent, et peut également ajouter de nouveaux attributs ou redéfinir les méthodes héritées.
Syntaxe :
class ClasseEnfant(ClasseParent):
# Nouvelle classe avec des attributs et méthodes hérités
Exemple de base : Héritage simple
class Animal:
def __init__(self, nom):
self.nom = nom
def parler(self):
print("L'animal fait un bruit.")
class Chien(Animal):
def parler(self):
print(f"{self.nom} aboie.")
class Chat(Animal):
def parler(self):
print(f"{self.nom} miaule.")
# Création d'objets Chien et Chat
rex = Chien("Rex")
rex.parler() # Affiche "Rex aboie."
minou = Chat("Minou")
minou.parler() # Affiche "Minou miaule."
Dans cet exemple, Chien
et Chat
sont des sous-classes de Animal
. Elles héritent de l'attribut nom
et redéfinissent la méthode parler()
pour adapter le comportement à chaque animal.
2. Héritage multiple
Python prend en charge l'héritage multiple, permettant à une classe d'hériter de plusieurs classes parent. Cela permet de combiner les comportements de différentes classes dans une seule classe enfant.
Syntaxe de l'héritage multiple :
class ClasseEnfant(ClasseParent1, ClasseParent2):
# La classe hérite des attributs et méthodes de plusieurs classes
Exemple : Héritage multiple
class Terrestre:
def deplacer(self):
print("Se déplace sur la terre.")
class Aquatique:
def nager(self):
print("Nage dans l'eau.")
class Amphibien(Terrestre, Aquatique):
pass
grenouille = Amphibien()
grenouille.deplacer() # Affiche "Se déplace sur la terre."
grenouille.nager() # Affiche "Nage dans l'eau."
Ici, la classe Amphibien
hérite à la fois des classes Terrestre
et Aquatique
, et peut donc accéder aux méthodes des deux parents.
Attention à l'héritage multiple
L'héritage multiple peut entraîner des ambiguïtés dans l'ordre de résolution des méthodes (MRO : Method Resolution Order). Python utilise un algorithme appelé C3 Linearization pour déterminer l'ordre des méthodes à appeler.
3. Le polymorphisme en Python
Le polymorphisme est la capacité de traiter des objets de classes différentes de la même manière, à condition qu'ils partagent une interface commune (même méthode). En Python, le polymorphisme est souvent utilisé avec des méthodes qui partagent le même nom dans plusieurs classes.
Exemple de polymorphisme :
class Chien:
def parler(self):
return "Aboie"
class Chat:
def parler(self):
return "Miaule"
# Fonction polymorphique
def faire_parler(animal):
print(animal.parler())
# Utilisation
rex = Chien()
minou = Chat()
faire_parler(rex) # Affiche "Aboie"
faire_parler(minou) # Affiche "Miaule"
Ici, la fonction faire_parler()
peut accepter un objet Chien
ou Chat
car ces deux classes implémentent une méthode parler()
. Python détermine dynamiquement la méthode à appeler en fonction de l'objet.
4. Méthodes redéfinies et super()
En Python, les classes enfant peuvent redéfinir les méthodes de la classe parent pour adapter leur comportement. Lorsque vous redéfinissez une méthode, il est parfois utile d'appeler la méthode du parent pour conserver une partie de la logique existante. Python fournit pour cela la fonction super()
.
Syntaxe :
class ClasseEnfant(ClasseParent):
def methode(self):
super().methode() # Appel de la méthode de la classe parent
Exemple avec super()
class Animal:
def __init__(self, nom):
self.nom = nom
def parler(self):
print("L'animal fait un bruit.")
class Chien(Animal):
def __init__(self, nom, race):
super().__init__(nom) # Appel du constructeur de Animal
self.race = race
def parler(self):
super().parler() # Appel de la méthode parler() de Animal
print(f"{self.nom} aboie.")
# Création d'un objet Chien
rex = Chien("Rex", "Berger Allemand")
rex.parler()
# Affiche :
# L'animal fait un bruit.
# Rex aboie.
Dans cet exemple, super()
appelle le constructeur de la classe Animal
pour initialiser nom
et la méthode parler()
de Animal
avant d’ajouter du comportement spécifique pour Chien
.
5. Polymorphisme et classes abstraites
Les classes abstraites sont des classes qui servent de modèle de base et ne peuvent pas être instanciées directement. Elles contiennent des méthodes sans implémentation, appelées méthodes abstraites, qui doivent être implémentées par les classes dérivées. En Python, vous pouvez créer des classes abstraites en utilisant le module abc
(Abstract Base Classes).
Syntaxe pour les classes abstraites :
from abc import ABC, abstractmethod
class ClasseAbstraite(ABC):
@abstractmethod
def methode_abstraite(self):
pass
Exemple : Classe abstraite pour animaux
from abc import ABC, abstractmethod
class Animal(ABC):
def __init__(self, nom):
self.nom = nom
@abstractmethod
def parler(self):
pass
class Chien(Animal):
def parler(self):
return "Aboie"
class Chat(Animal):
def parler(self):
return "Miaule"
# Utilisation du polymorphisme
animaux = [Chien("Rex"), Chat("Minou")]
for animal in animaux:
print(animal.parler())
Dans cet exemple, Animal
est une classe abstraite avec une méthode parler
sans implémentation. Les classes Chien
et Chat
sont obligées d'implémenter parler
pour être instanciées.
Conclusion
L'héritage et le polymorphisme en Python permettent de structurer et d'étendre les fonctionnalités de vos classes. Avec l'héritage, vous pouvez réutiliser et étendre des fonctionnalités existantes, et avec le polymorphisme, vous pouvez travailler de manière uniforme avec différents types d'objets. Ces concepts rendent votre code plus modulaire, maintenable et évolutif, ce qui est essentiel pour tout programme complexe en Python.