Le duck typing est un principe fondamental du Python selon lequel un objet est évalué par son comportement plutôt que par son appartenance à une hiérarchie de classes.
Le terme provient du proverbe : "Si quelque chose ressemble à un canard, nage comme un canard et cancane comme un canard, alors c'est un canard". En Python, le comportement d'un objet (son interface) est plus important que la classe à laquelle il appartient. Cela met en œuvre le principe du "duck typing" — la typage par comportement (typage structurel).
On pourrait penser que le duck typing offre une flexibilité maximale. Mais cela augmente le nombre de bugs cachés : le programme "casse" uniquement lors de l'exécution, si un objet ne supporte pas l'interface requise.
Au lieu de vérifier le type (via isinstance ou type), écrivez des fonctions qui essaient d'appeler les méthodes nécessaires sur l'objet, en supposant que si l'objet les supporte, tout fonctionnera. En dernier recours, attrapez les exceptions AttributeError ou TypeError pour gérer les objets inattendus.
Exemple :
def quack_and_walk(duck): duck.quack() duck.walk() class Robot: def quack(self): print("Je peux cancaner !") def walk(self): print("Je marche") quack_and_walk(Robot()) # tout fonctionnera !
Caractéristiques clés :
Peut-on vérifier le type en Python avec isinstance et dire que c'est correct pour le duck typing ?
Non. Le duck typing s'oppose en fait à la vérification stricte des types. Il est plus judicieux d'opérer sur le comportement de l'objet plutôt que sur sa lignée.
Peut-on implémenter le duck typing à l'aide de classes abstraites de base (ABC) ?
Partiellement. Les classes abstraites introduisent des éléments de structure statique. Le duck typing ne nécessite pas de déclarer une parenté — il suffit d'implémenter les méthodes requises. Mais depuis Python 3.8, le module typing.Protocol nous rapproche du typage structurel.
Le duck typing peut-il fonctionner avec des méthodes magiques (len, getitem etc.) ?
Oui. Si un objet implémente la méthode requise (len), il peut être passé à des fonctions, par exemple, len(obj), et cela fonctionnera selon le duck typing.
Un développeur écrit une fonction qui accepte tout objet avec une méthode run(), sans vérification. Dans le code apparaît un objet sans cette méthode — et l'erreur n'apparaît qu'au moment de l'exécution.
Avantages :
Inconvénients :
Utilisation du duck typing, mais avec try/except et documentation de l'interface :
def run_task(obj): try: obj.run() except AttributeError: print("L'objet ne prend pas en charge l'exécution de la tâche !")
Avantages :
Inconvénients :