Polymorphisme en Python

24 Apr 2019 24 Apr 2019 17198 vues ESSADDOUKI Mostafa

Polymorphisme

Définition — Polymorphisme Le mot polymorphisme vient du grec : poly (plusieurs) + morphe (forme). En POO, il désigne la capacité de plusieurs classes à fournir une implémentation différente d'une méthode portant le même nom. Un même appel de méthode produit ainsi des comportements différents selon le type réel de l'objet au moment de l'exécution.

En Python, le polymorphisme se manifeste principalement par la redéfinition de méthode (method overriding) : une classe enfant réimplémente une méthode héritée de sa classe mère pour adapter son comportement à ses besoins spécifiques.

Forme de polymorphismeDescriptionMécanisme Python
Redéfinition (overriding)La sous-classe réimplémente une méthode du parentMême nom de méthode dans la sous-classe
Duck typingTout objet ayant la méthode attendue est acceptéPas de vérification de type explicite
Fonctions polymorphesUne fonction accepte tout objet ayant une méthode donnéeAppel générique obj.methode()

Redéfinition de méthode (Method Overriding)

Définition — Méthode redéfinie Une méthode redéfinie est une méthode déclarée dans une classe enfant avec le même nom qu'une méthode de la classe mère. Lors de l'appel, Python utilise automatiquement la version de la classe réelle de l'objet, pas celle du parent.

Syntaxe Python
class Parent:
    def methode(self):
        # implémentation par défaut
        ...

class Enfant(Parent):
    def methode(self):      # redéfinition — même nom
        # implémentation spécifique à Enfant
        ...

Exemple — Hiérarchie Personne → Etudiant / Professeur

class Personne:
    def __init__(self, nom):
        self.nom = nom

    def afficher(self):
        print(f"Je suis une personne. Nom : {self.nom}")


class Etudiant(Personne):
    def __init__(self, nom, cne):
        super().__init__(nom)
        self.cne = cne

    def afficher(self):     # redéfinition de afficher()
        print(f"Je suis un étudiant. Nom : {self.nom} | CNE : {self.cne}")


class Professeur(Personne):
    def __init__(self, nom, ppr):
        super().__init__(nom)
        self.ppr = ppr

    def afficher(self):     # redéfinition de afficher()
        print(f"Je suis un professeur. Nom : {self.nom} | PPR : {self.ppr}")


# Polymorphisme en action — même appel, comportements différents
personnes = [
    Etudiant('Kayouh', 123444),
    Professeur('ESSADDOUKI', 123123123),
    Personne('Alami')
]

for obj in personnes:
    obj.afficher()          # appelle la version propre à chaque classe
Sortie
Je suis un étudiant.  Nom : Kayouh     | CNE : 123444
Je suis un professeur. Nom : ESSADDOUKI | PPR : 123123123
Je suis une personne.  Nom : Alami
Comment Python choisit-il la bonne méthode ? Python utilise le MRO (Method Resolution Order) pour déterminer quelle version d'une méthode appeler. Il cherche d'abord dans la classe de l'objet, puis remonte dans les classes parentes. On peut consulter le MRO avec NomClasse.__mro__.
print(Etudiant.__mro__)
# (, , )

Polymorphisme avec des fonctions

Python permet de créer des fonctions polymorphes : des fonctions qui acceptent n'importe quel objet possédant une méthode donnée, sans se soucier de son type réel. C'est le principe du duck typing : « Si ça marche comme un canard et que ça fait coin-coin, c'est un canard. »

Duck Typing En Python, on ne vérifie pas le type d'un objet, mais son comportement : si l'objet possède la méthode appelée, ça fonctionne. Pas besoin d'interface formelle ni de déclaration explicite.

Exemple — Fonction polymorphe afficher_infos()

def afficher_infos(obj):
    """Fonctionne avec tout objet ayant une méthode afficher()."""
    print(type(obj).__name__, "→", end=" ")
    obj.afficher()

etd = Etudiant('Kayouh', 123444)
prf = Professeur('ESSADDOUKI', 123123123)
per = Personne('Alami')

afficher_infos(etd)
afficher_infos(prf)
afficher_infos(per)
Sortie
Etudiant   → Je suis un étudiant.  Nom : Kayouh     | CNE : 123444
Professeur → Je suis un professeur. Nom : ESSADDOUKI | PPR : 123123123
Personne   → Je suis une personne.  Nom : Alami

Exemple — Duck typing avec classes sans lien d'héritage

Le polymorphisme en Python ne nécessite pas obligatoirement l'héritage. Deux classes totalement indépendantes peuvent être utilisées de façon polymorphe si elles partagent le même nom de méthode.

class Chien:
    def parler(self):
        print("Woof !")

class Chat:
    def parler(self):
        print("Miaou !")

class Perroquet:
    def parler(self):
        print("Bonjour !")

def faire_parler(animal):
    animal.parler()   # fonctionne pour tout objet ayant parler()

animaux = [Chien(), Chat(), Perroquet()]
for a in animaux:
    faire_parler(a)
Sortie
Woof !
Miaou !
Bonjour !

Aller plus loin — Méthodes abstraites

Pour forcer les sous-classes à redéfinir une méthode, Python propose le module abc (Abstract Base Classes). Une méthode abstraite déclarée dans la classe mère doit obligatoirement être implémentée dans chaque sous-classe.

from abc import ABC, abstractmethod

class Personne(ABC):
    def __init__(self, nom):
        self.nom = nom

    @abstractmethod
    def afficher(self):
        """Chaque sous-classe DOIT implémenter cette méthode."""
        pass

class Etudiant(Personne):
    def __init__(self, nom, cne):
        super().__init__(nom)
        self.cne = cne

    def afficher(self):   # obligatoire
        print(f"Étudiant : {self.nom} | CNE : {self.cne}")

# Personne()   → TypeError : impossible d'instancier une classe abstraite
etd = Etudiant('Kayouh', 123444)
etd.afficher()
Sortie
Étudiant : Kayouh | CNE : 123444
Remarque Tenter d'instancier directement une classe abstraite (Personne()) lève une TypeError. Cela garantit que toutes les sous-classes implémentent bien les méthodes requises.

Récapitulatif

ConceptRôleExemple
RedéfinitionAdapter le comportement d'une méthode héritéeafficher() dans Etudiant
Duck typingAppeler une méthode sans vérifier le typeobj.afficher() dans une boucle
Fonction polymorpheAccepter tout objet ayant la méthode attendueafficher_infos(obj)
Classe abstraiteForcer la redéfinition dans les sous-classes@abstractmethod + ABC
MROOrdre de recherche des méthodesClasse.__mro__