Comment appliquer le polymorphisme aux classes de Python 3

introduction

Polymorphism est la possibilité de tirer parti de la même interface pour différentes formes sous-jacentes telles quedata types ouclasses. Cela permet àfunctions d'utiliser des entités de types différents à des moments différents.

Pour la programmation orientée objet en Python, cela signifie qu'un objet particulier appartenant à une classe particulière peut être utilisé de la même manière que s'il s'agissait d'un objet différent appartenant à une classe différente.

Le polymorphisme permet une flexibilité et un couplage lâche afin que le code puisse être étendu et maintenu facilement dans le temps.

Ce tutoriel va appliquer le polymorphisme à des classes en Python.

Qu'est-ce que le polymorphisme?

Le polymorphisme est une fonctionnalité importante de la définition de classe en Python qui est utilisée lorsque vous nommez des méthodes de différentes classes ou sous-classes. Cela permet aux fonctions d'utiliser des objets de l'une de ces classes polymorphes sans avoir à connaître les distinctions entre les classes.

Le polymorphisme peut être effectué viainheritance, les sous-classes utilisant des méthodes de classe de base ou les surchargeant.

Lesduck typing de Python, un cas particulier de typage dynamique, utilise des techniques caractéristiques du polymorphisme, y comprislate binding etdynamic dispatch. Le terme "typage de canard" est dérivé d'une citation de l'écrivain James Whitcomb Riley: "Quand je vois un oiseau qui marche comme un canard et qui nage comme un canard et qui charrie comme un canard, j'appelle cet oiseau un canard." Approprié par Italian ingénieur en informatique Alex Martelli, dans un message destiné au groupe de discussion comp.lang.python, l’utilisation du typage de canard a pour objectif d’établir l’adéquation d’un objet à un usage spécifique. Lorsque vous utilisez le typage normal, cette aptitude est déterminée par le type d'un objet uniquement, mais avec le typage de canard, la présence de méthodes et de propriétés est utilisée pour déterminer l'adéquation plutôt que le type réel de l'objet en question. C'est-à-dire que vous vérifiez si l'objet pique comme un canard et marche comme un canard plutôt que de demander si l'objetisest un canard.

Lorsque plusieurs classes ou sous-classes ont les mêmes noms de méthodes, mais des implémentations différentes pour ces mêmes méthodes, les classes sont polymorphes car elles utilisent une seule interface à utiliser avec des entités de types différents. Une fonction pourra évaluer ces méthodes polymorphes sans savoir quelles classes sont appelées.

Création de classes polymorphes

Pour utiliser le polymorphisme, nous allons créer deux classes distinctes à utiliser avec deux objets distincts. Chacune de ces classes distinctes doit avoir une interface commune pour pouvoir être utilisée de manière polymorphe. Nous allons donc leur attribuer des méthodes distinctes, mais portant le même nom.

Nous allons créer une classeShark et une classeClownfish, chacune définissant des méthodes pourswim(),swim_backwards() etskeleton().

polymorphic_fish.py

class Shark():
    def swim(self):
        print("The shark is swimming.")

    def swim_backwards(self):
        print("The shark cannot swim backwards, but can sink backwards.")

    def skeleton(self):
        print("The shark's skeleton is made of cartilage.")


class Clownfish():
    def swim(self):
        print("The clownfish is swimming.")

    def swim_backwards(self):
        print("The clownfish can swim backwards.")

    def skeleton(self):
        print("The clownfish's skeleton is made of bone.")

Dans le code ci-dessus, les classesShark etClownfish ont trois méthodes avec le même nom en commun. Cependant, chacune des fonctionnalités de ces méthodes diffère pour chaque classe.

Instancions ces classes en deux objets:

polymorphic_fish.py

...
sammy = Shark()
sammy.skeleton()

casey = Clownfish()
casey.skeleton()

Lorsque nous exécutons le programme avec la commandepython polymorphic_fish.py, nous pouvons voir que chaque objet se comporte comme prévu:

OutputThe shark's skeleton is made of cartilage.
The clownfish's skeleton is made of bone.

Maintenant que nous avons deux objets qui utilisent une interface commune, nous pouvons les utiliser de la même manière, indépendamment de leurs types individuels.

Polymorphisme avec les méthodes de classe

Pour montrer comment Python peut utiliser chacun de ces différents types de classes de la même manière, nous pouvons d'abord créer unfor loop qui itère à travers untuple d'objets. Ensuite, nous pouvons appeler les méthodes sans nous préoccuper du type de classe de chaque objet. Nous supposerons seulement que ces méthodes existent réellement dans chaque classe.

polymorphic_fish.py

...
sammy = Shark()

casey = Clownfish()

for fish in (sammy, casey):
    fish.swim()
    fish.swim_backwards()
    fish.skeleton()

Nous avons deux objets,sammy de la classeShark etcasey de la classeClownfish. Notre bouclefor itère à travers ces objets, appelant les méthodesswim(),swim_backwards() etskeleton() sur chacun.

Lorsque nous exécutons le programme, le résultat sera le suivant:

OutputThe shark is swimming.
The shark cannot swim backwards, but can sink backwards.
The shark's skeleton is made of cartilage.
The clownfish is swimming.
The clownfish can swim backwards.
The clownfish's skeleton is made of bone.

La bouclefor s'est itérée d'abord via l'instanciationsammy de la classeShark, puis l'objetcasey de la classeClownfish, nous voyons donc les méthodes liées la classeShark en premier, puis la classeClownfish.

Cela montre que Python utilise ces méthodes d'une manière qui ignore ou ne se soucie pas du type de classe de chacun de ces objets. C'est-à-dire, utiliser ces méthodes de manière polymorphe.

Polymorphisme avec une fonction

Nous pouvons également créer une fonction pouvant prendre n’importe quel objet, permettant ainsi un polymorphisme.

Créons une fonction appeléein_the_pacific() qui prend un objet que nous pouvons appelerfish. Bien que nous utilisions le nomfish, tout objet instancié pourra être appelé dans cette fonction:

polymorphic_fish.py

…
def in_the_pacific(fish):

Ensuite, nous allons donner à la fonction quelque chose à faire qui utilise l'objetfish que nous lui avons passé. Dans ce cas, nous appellerons les méthodesswim(), dont chacune est définie dans les deux classesShark etClownfish:

polymorphic_fish.py

...
def in_the_pacific(fish):
    fish.swim()

Ensuite, nous allons créer des instanciations des classesShark etClownfish si nous ne les avons pas déjà. Avec ceux-ci, nous pouvons appeler leur action en utilisant la même fonctionin_the_pacific():

polymorphic_fish.py

...
def in_the_pacific(fish):
    fish.swim()

sammy = Shark()

casey = Clownfish()

in_the_pacific(sammy)
in_the_pacific(casey)

Lorsque nous exécutons le programme, le résultat sera le suivant:

OutputThe shark is swimming.
The clownfish is swimming.

Même si nous avons passé un objet aléatoire (fish) dans la fonctionin_the_pacific() lors de sa définition, nous avons quand même pu l'utiliser efficacement pour les instanciations des classesShark etClownfish . L'objetcasey appelé la méthodeswim() définie dans la classeClownfish, et l'objetsammy appelé la méthodeswim() définie dans la classeShark .

Conclusion

En permettant à différents objets d'exploiter les fonctions et les méthodes de la même manière grâce au polymorphisme, l'utilisation de cette fonctionnalité Python offre une plus grande flexibilité et une plus grande extensibilité de votre code orienté objet.