Polymorphisme
Le polymorphisme est un concept fondamental en programmation orientée objet. Il permet de définir des méthodes dans une classe de base qui peuvent être redéfinies dans les classes dérivées. Cela permet à un objet d'une classe dérivée d'être traité comme un objet de la classe de base, mais avec un comportement spécifique à la classe dérivée. Ce type de polymorphisme est appelé polymorphisme d'inclusion ou de sous-typage.
Surcharge de méthodes
En Python, le polymorphisme est généralement réalisé par la surcharge de méthodes. Cela signifie que vous pouvez définir une méthode dans une classe de base, puis la redéfinir dans une classe dérivée.
Par exemple, vous pouvez définir une classe Animal
avec une méthode parler
, puis
définir une classe Chien
qui hérite de Animal
et redéfinit la méthode parler
pour
qu'elle affiche "Le chien aboie". Voici un exemple :
class Animal:
def parler(self):
print("L'animal parle.")
class Chien(Animal):
def parler(self):
print("Le chien aboie.")
animal = Animal()
chien = Chien()
for el in [animal, chien]:
el.parler() # Affiche : L'animal parle. puis Le chien aboie.
Comme on peut le voir, la méthode parler
de la classe Chien
remplace
celle de la classe Animal
. De plus, dans ce code la liste contient des objets de
type Animal
et Chien
, mais la méthode parler
appelée est commune aux deux
objets et donc le code fonctionne correctement.
Extension de méthodes
Si l'on souhaite que la méthode de la classe dérivée appelle la méthode de la
classe de base, on peut utiliser le mot-clé super()
. Cela permet d'appeler la
méthode de la classe de base depuis la classe dérivée. Voici un exemple :
class Animal:
def parler(self):
print("L'animal parle.")
class Chien(Animal):
def parler(self):
super().parler() # Appelle la méthode de la classe de base
print("Le chien aboie.")
chien = Chien()
chien.parler() # Affiche : L'animal parle. puis Le chien aboie.
Polymorphisme et typage canard
Puisque tout est comme un dictionnaire en Python, le polymorphisme est très facile à mettre en œuvre. Lorsque vous appelez une méthode sur un objet, Python cherche d'abord la méthode dans le dictionnaire de l'objet. Si la signature de la méthode est trouvée, Python appelle la méthode. Sinon, Python remonte la chaîne d'héritage pour trouver la méthode.
Ainsi, il n'est même pas nécessaire d'hériter d'une classe mère pour avoir une méthode en commun. Vous pouvez simplement ajouter une méthode à un objet existant qui a la même signature qu'une méthode de la classe mère.
class Animal:
def parler(self):
print("L'animal parle.")
class Chien:
def parler(self):
print("Le chien aboie.")
animal = Animal()
chien = Chien()
for el in [animal, chien]:
el.parler() # La méthode parler est disponible pour les deux objets.
C'est ce qu'on appelle le typage canard en programmation orientée objet. Si
un objet a la méthode parler
, alors il peut être traité comme une instance
d'une classe qui a la méthode parler
.
Quand utiliser le typage canard ?
De façon à bien structurer votre code, il est recommandé de définir des classes mères, des classes abstraites ou des interfaces pour garantir que les méthodes sont redéfinies dans les classes filles. Cela permet de rendre votre code plus lisible et plus facile à maintenir. Cela évite aussi de dupliquer du code.
Néanmoins, l'utilisation du typage canard permet de ne pas avoir à utiliser l'héritage pour obtenir du polymorphisme. Vous pouvez simplement ajouter des méthodes à des objets existants pour obtenir le même effet. Cela est très utile lorsque vous devez interagir avec des objets qui ne sont pas sous votre contrôle, comme ceux provenant de bibliothèques tierces ou de la bibliothèque standard.
Par exemple, la fonction open
de Python retourne un objet qui représente un
fichier. L'objet retourné par open
a plusieurs méthodes, mais si votre code n'a besoin
que de la méthode read
, vous pouvez simplement ajouter cette méthode à un objet
existant pour obtenir le même effet.
class MonFichier:
def __init__(self, contenu):
self.contenu = contenu
def read(self):
return self.contenu
f = MonFichier("Hello, world!")
print(f.read()) # Affiche : Hello, world!
Ainsi, chaque fois qu'une fonction dans votre code a besoin d'un fichier et
utilise uniquement la méthode read
, vous pouvez simplement lui passer un
objet MonFichier
. Ceci est beaucoup plus flexible et bien plus simple que
d'utiliser l'héritage.