Aller au contenu
M03 · B. Connaître les principaux piliers de la POO

Le polymorphisme : un même appel, des comportements différents

Redéfinir une méthode dans une classe fille, traiter des objets différents de façon uniforme, et surcharger les méthodes et les opérateurs en Python.

1Situer

Un atelier de menuiserie à Tétouan calcule la surface de bois nécessaire pour ses commandes : des plateaux rectangulaires, des tables rondes, des étagères triangulaires. Le programme doit parcourir toutes les pièces d'une commande et additionner leurs aires, sans écrire un « si c'est un cercle alors... sinon si c'est un rectangle... ». C'est exactement ce que permet le polymorphisme.

2Comprendre

Polymorphisme : le même appel, des calculs différents
for piece in commande: total += piece.aire() Rectanglel × L Disqueπ × r² Rectanglel × L 1,28 1,13 0,36 total = 0

La commande contient trois pièces de classes différentes. La boucle appelle piece.aire() sur chacune.

1 / 5

Polymorphisme veut dire « plusieurs formes ». Un même appel, piece.aire(), déclenche un calcul différent selon la classe réelle de l’objet.

La redéfinition de méthode

Une classe fille peut redéfinir (override) une méthode héritée : elle écrit une méthode de même nom qui remplace celle de la mère. Pour réutiliser la version de la mère, on appelle super().methode().

for piece in commande:
    total += piece.aire()   # Rectangle.aire() ou Disque.aire()

Ajouter une nouvelle sorte de pièce ne demande aucune modification de la boucle : c’est l’intérêt principal du polymorphisme.

La surcharge de méthode

En Java ou en C#, on peut écrire plusieurs méthodes de même nom avec des paramètres différents. En Python, la dernière définie gagne. On obtient le même résultat avec des paramètres par défaut :

def aire(self, unite="m2"):
    ...

La surcharge d’opérateurs

Python appelle des méthodes spéciales quand on utilise un opérateur sur un objet :

ÉcritureMéthode appelée
a + ba.__add__(b)
a == ba.__eq__(b)
a < ba.__lt__(b)
print(a)a.__str__()
len(a)a.__len__()

En les définissant, vos objets s’utilisent aussi naturellement que des nombres ou des chaînes.

Exemple simple

« Fais ton cri »

Demandez à un chat, un chien et un coq de « faire leur cri » : chacun répond à sa manière. La demande est la même, la réponse dépend de l'animal.

for animal in [Chat(), Chien(), Coq()]:
    animal.crier()   # Miaou / Ouaf / Cocorico
Exemple simple

Le + qui s'adapte

En Python, + additionne des nombres, colle des textes et fusionne des listes. C'est déjà du polymorphisme : le même opérateur se comporte selon le type.

print(2 + 3)             # 5
print("Dar" + "ija")     # Darija
print([1, 2] + [3])      # [1, 2, 3]

3Manipuler

Exécutez. Une seule boucle calcule toutes les aires. Ajoutez une classe Triangle(base, hauteur) avec sa propre méthode aire(), mettez un triangle dans la commande, et relancez : la boucle n'a pas besoin de changer.
Pas à pas dans le lab ↗Python se charge au premier clic (environ 12 Mo, une seule fois).
Console
Mémoire : objets créés

Exécutez le code : les objets et leurs attributs s'afficheront ici.

4Pratiquer

Exercice 1 · Le triangle

Ajoutez la classe Triangle(nom, base, hauteur) avec sa méthode aire(). Vérifiez que la boucle de la commande fonctionne sans modification.

Voir le corrigé
class Triangle(Piece):
    def __init__(self, nom, base, hauteur):
        super().__init__(nom)
        self.base, self.hauteur = base, hauteur

    def aire(self):
        return self.base * self.hauteur / 2

commande.append(Triangle("Équerre", 0.4, 0.4))

Exercice 2 · Surcharge d'opérateur

Écrivez une classe Prix(montant) dont les objets s'additionnent avec + et se comparent avec <. Testez Prix(20) + Prix(15) et Prix(20) < Prix(15).

Voir un indice

Les méthodes spéciales s'appellent __add__ et __lt__.

Voir le corrigé
class Prix:
    def __init__(self, montant):
        self.montant = montant
    def __add__(self, autre):
        return Prix(self.montant + autre.montant)
    def __lt__(self, autre):
        return self.montant < autre.montant
    def __str__(self):
        return f"{self.montant} DH"

print(Prix(20) + Prix(15))   # 35 DH
print(Prix(20) < Prix(15))   # False

Exercice 3 · Redéfinir en gardant le comportement parent

Dans une classe Taxi(Voiture), redéfinissez decrire() pour ajouter « (taxi) » à la description de la classe mère, sans la recopier.

Voir le corrigé
class Taxi(Voiture):
    def decrire(self):
        return super().decrire() + " (taxi)"

5Vérifier

1. Qu'est-ce que la redéfinition (override) d'une méthode ?
2. Python permet-il d'écrire deux méthodes de même nom avec des paramètres différents dans une même classe ?
3. Quelle méthode spéciale permet d'utiliser + entre deux objets ?