Modification du comportement intégré à l’aide de méthodes magiques
Les méthodes magiques sont des méthodes spéciales que vous pouvez définir pour ajouter de la « magie » à vos classes. Ils sont toujours entourés de doubles traits de soulignement, par exemple, les méthodes magiques __init__ et __str__. Les méthodes magiques peuvent enrichir notre conception de classe en nous donnant accès aux fonctionnalités de syntaxe intégrées de Python.
Python permet à nos classes d’hériter des classes intégrées. Une classe enfant héritière d’un élément intégré partage tous les mêmes attributs, y compris les méthodes que l’élément intégré. Nous pouvons tirer parti des fonctionnalités intégrées de base, mais personnaliser les opérations sélectionnées grâce à l’utilisation de méthodes magiques.
Dans ce tutoriel, je vais lier ces deux idées ensemble pour montrer comment nous pouvons hériter de la classe list intégrée et utiliser des méthodes magiques dans la conception de notre classe. Je vais modifier les trois méthodes magiques qui contrôlent l’indexation de la liste. En combinant ces deux fonctionnalités, une classe très simple à utiliser peut être construite et nous pouvons ajouter un comportement aux méthodes que nous désirons. Le comportement intégré est familier à tous les développeurs Python; à son tour, cela rend l’utilisation de notre classe héritière facile à apprendre.
Enfin, deux autres exemples plus larges illustrant comment les méthodes magiques peuvent être utilisées dans les opérations de diffusion et la modification de l’état d’une instance seront démontrés. Tout le code d’accompagnement est disponible via GitHub.
Exemple 1: Indexation de liste
Les méthodes magiques peuvent être manipulées pour modifier l’indexation de liste. La classe MyCustomList hérite du type de liste intégré. Cela signifie que tout objet créé via la classe MyCustomList se comportera comme une liste, sauf aux endroits où nous choisissons de personnaliser sélectivement les méthodes.
getitem, setitem et delitem sont des méthodes magiques qui sont invoquées lorsque nous accédons à l’index de la liste. Le comportement de ces méthodes magiques peut être modifié.
Dans l’exemple ci-dessous, nous rejetons l’idée d’une indexation de liste commençant par l’index zéro. Si l’utilisateur tente d’accéder à un élément de notre liste à l’aide de l’index zeroth, une exception ValueError sera levée et le programme se terminera. Si l’utilisateur entre un index de liste supérieur à un, les méthodes réduiront l’index d’un, puis appelleront la liste des classes parentes avec l’index.
Pour montrer comment ces méthodes définies dans la classe MyCustomList sont utilisées, voir ci-dessous dans l’invite interactive Python.
L’exemple montre comment getitem, setitem et delitem peuvent être appelés. Les méthodes magiques peuvent être appelées implicitement. Pour __getitem__, pour accéder au premier index, il suffit d’écrire le nom de l’objet suivi de la position de l’index entre crochets.
Ce qui est le plus intéressant, c’est que lorsque nous demandons l’élément à la position d’index 1, la valeur entière 1 est renvoyée, même si 1 est l’élément zéro. Ce que nous avons ici est une liste qui commence son indexation à partir de 1. En fait, cela compense la confusion que nous avons tous eue lorsque nous avons appris l’indexation des listes pour la première fois.
Maintenant, changeons la valeur entière 1 dans la liste en 100. Pour ce faire, nous devons invoquer setitem. Pour ce faire, nous écrivons simplement le nom de l’objet, suivi de crochets et d’une affectation. Encore une fois, pour changer le premier élément de la liste, nous utilisons la position d’index 1. Lorsque nous sortons à nouveau la liste, nous pouvons clairement voir que le premier élément est passé de 1 à 100.
Enfin, pour supprimer un élément de la liste __delitem__ peut être défini. La méthode magique __delitem__ est invoquée lorsque nous utilisons le mot clé del python qui se résout en appel de méthode __delitem__. Pour continuer sur notre exemple d’indexation de liste, supprimons le premier élément de l’index, la valeur entière 100. Lorsque nous appelons del, suivi de l’objet et de la position d’index de l’élément que nous voulons supprimer, dans cet exemple, le premier élément de la liste 100, nous pouvons maintenant voir que 100 a en fait été supprimé!
Les méthodes magiques offrent la possibilité de modifier le comportement par défaut. Mieux encore, il n’est pas nécessaire d’apprendre de nouveaux noms de méthodes ou une nouvelle interface, de sorte que les méthodes peuvent être implémentées intuitivement. Un guide d’utilisation de ces méthodes magiques implémentées dans MyCustomList est spécifié dans le tableau ci-dessous.
Example 2: La méthode magique __mul__
Nous pouvons également utiliser l’opérateur de multiplication dans notre conception de classe. Puisque nous héritons de la classe list intégrée, nous pouvons compresser deux objets MyCustomList ensemble (car ils agissent comme des objets list) et parcourir l’objet zip. Au cours des itérations, nous pouvons multiplier les éléments de chaque liste par son élément correspondant dans l’autre liste de manière diffusée (voir l’extrait de code de méthode magique __mul__ ci-dessous). Ce comportement de diffusion est similaire à celui des packages d’analyse de données tels que Pandas et Numpy.
L’exemple montre que nous pouvons multiplier deux objets MyCustomList ensemble en utilisant le signe *. Si nous capturons la valeur renvoyée dans une variable appelée list_three et imprimons list_three, une nouvelle liste est sortie. Cette liste est le produit de la multiplication des éléments les uns par rapport aux autres à partir des 2 autres listes.
L’ensemble du code source de la classe utilisée dans cet exemple, MyCustomList est affiché ci-dessous:
Exemple de bonus: La méthode __call__magic
Pour terminer, je vais illustrer comment la méthode __call__magic en Python peut être invoquée. __call__
peut être particulièrement utile dans les classes avec des instances qui doivent souvent changer d’état. « Appeler » l’instance peut être un moyen intuitif et élégant de changer l’état de l’objet.
Considérons l’exemple illustré. Ici, la classe MyClass a un constructeur d’initialisation qui attend trois arguments passés. Ces trois arguments peuvent être passés dans la signature de la méthode init et attribués en tant qu’attributs dans l’objet.
La méthode call magic est utile lorsque nous voulons changer l’état d’une instance, sans créer réellement une nouvelle instance.
Lorsque l’instance est initialisée pour la première fois, je passe les entiers 1, 2 et 3, qui sont affectés en tant qu’attributs var_1, var_2 et var_3 dans l’instance respectivement. Lorsque j’utilise l’instruction print pour afficher la sortie de l’instance, obj, en utilisant l’attribut __dict__, je peux voir que var_1 reçoit la valeur 1, var_2 la valeur 2 et var_3 la valeur 3.
Maintenant, proposons que je voudrais changer les valeurs d’attribut var_1 et var_2 de cette instance, tout en gardant l’attribut var_3 tel qu’il était lors de la construction de l’instance.
Pour ce faire, c’est simple. Je définis une méthode magique d’appel, qui permet de redéfinir les attributs var_1 et var_2. Les méthodes magiques peuvent être appelées implicitement, ce qui signifie que j’appelle simplement obj(200, 300), et la méthode d’appel sera invoquée. Bien entendu, il est également possible d’invoquer explicitement la méthode call, par exemple obj.__appelez __(200, 300), mais la première méthode semble plus intuitive. Enfin, à des fins de démonstration, j’ai imprimé l’ID de l’instance pour montrer définitivement que nous avons manipulé le même objet.
La méthode d’appel peut être définie de deux manières. Les arguments peuvent être transmis directement à la signature de la méthode d’appel. Alternativement, l’argument *vars peut être utilisé, qui capture tous les arguments passés et les stocke dans un tuple, qui peut être décompressé comme indiqué ci-dessus.
Le code source de cet exemple se trouve ci-dessous.
Résumé
Les méthodes magiques peuvent enrichir notre conception de classe en nous donnant accès aux fonctionnalités de syntaxe de base. Dans les premiers exemples, nous avons le meilleur des deux mondes. Nous pouvons hériter de la classe list intégrée et modifier des méthodes particulières dans cette classe pour personnaliser le comportement. getitem, setitem et delitem ont tous été modifiés, mais grâce à l’héritage, nous pouvions toujours utiliser les méthodes init et repr() intégrées à la liste par exemple.
Nous pouvons communiquer l’utilisation des objets très facilement aux autres développeurs. Dans l’exemple fourni, tout ce que nous devons dire à nos collègues développeurs, c’est que notre classe agit comme une liste, juste un peu différemment, ici nous rejetons l’idée d’un index zéro. Il n’est pas nécessaire d’apprendre un nouveau nom de méthode ou une nouvelle interface.
De plus, la méthode call magic a été démontrée. L’appel de l’instance peut être un moyen intuitif et élégant de modifier l’état de l’objet.