Une des capacités les plus discrètes mais pourtant extrêmement utiles de Python réside dans la possibilité de personnaliser le comportement des objets à travers des méthodes dites « magiques ». Ces méthodes permettent de concevoir un code plus net, intuitif et aisé à assimiler.
Grâce à ces méthodes magiques, il est possible de créer des interfaces qui permettent d’interagir avec les objets d’une façon plus « pythonique ». Cet article a pour objectif de vous initier aux méthodes magiques, d’étudier les meilleures pratiques pour les créer et d’explorer les méthodes magiques les plus fréquentes que vous serez amené à rencontrer.
Que sont les méthodes magiques ?
Les méthodes magiques sont des méthodes spécifiques à Python qui définissent la façon dont les objets Python se comportent lorsqu’on leur applique des opérations courantes. Ces méthodes se caractérisent par la présence de doubles tirets bas (underscores) avant et après le nom de la méthode.
C’est la raison pour laquelle on les appelle communément méthodes « dunder », contraction de « double underscore ». Une méthode dunder courante que vous avez certainement déjà croisée est la méthode __init__() qui sert à définir les constructeurs de classe.
En principe, les méthodes dunder ne sont pas conçues pour être invoquées directement dans votre code. Elles sont plutôt appelées par l’interpréteur durant l’exécution du programme.
Pourquoi les méthodes magiques sont-elles utiles ?
Les méthodes magiques représentent un concept fort utile dans le cadre de la programmation orientée objet avec Python. Elles permettent de déterminer le comportement de vos types de données personnalisés lorsqu’ils sont sollicités par des opérations intégrées courantes. Ces opérations comprennent :
- Opérations arithmétiques
- Opérations de comparaison
- Opérations de gestion du cycle de vie
- Opérations de représentation
La section suivante détaille la manière d’implémenter des méthodes magiques qui définissent le comportement de l’application dans chacune des catégories mentionnées ci-dessus.
Comment définir les méthodes magiques
Comme précisé précédemment, les méthodes magiques dictent le comportement des objets. En tant que telles, elles sont définies comme faisant partie intégrante de la classe de l’objet. Étant donné qu’elles sont rattachées à la classe d’objets, elles prennent comme premier argument self, qui renvoie à l’objet lui-même.
Elles peuvent également accepter des arguments supplémentaires selon la manière dont l’interpréteur les appellera. Elles se distinguent également par la présence de deux tirets bas avant et après leurs noms.
Mise en œuvre
Une grande partie de ce qui a été évoqué jusqu’à présent semble théorique et abstrait. Dans cette section, nous allons concrétiser tout cela en implémentant une classe Rectangle simple.
Cette classe possédera des propriétés telles que la longueur et la largeur. Grâce à la méthode __init__, il sera possible de spécifier ces propriétés au moment de l’instanciation. De plus, nous pourrons comparer différents rectangles pour déterminer s’ils sont égaux, inférieurs ou supérieurs à d’autres, en utilisant les opérateurs ==, < et >. Enfin, le rectangle devra pouvoir fournir une représentation sous forme de chaîne intelligible.
Configuration de l’environnement de codage
Pour suivre cette démonstration pas à pas, il vous faudra un environnement d’exécution Python. Vous pouvez opter pour un environnement local ou bien vous servir du compilateur Python en ligne de toptips.fr.
Création de la classe Rectangle
Pour commencer, définissons la classe Rectangle.
class Rectangle: pass
Création de la méthode constructeur
Ensuite, nous allons créer notre première méthode magique : la méthode du constructeur de classe. Cette méthode prendra la hauteur et la largeur et les enregistrera comme des attributs de l’instance de la classe.
class Rectangle: def __init__(self, height, width): self.height = height self.width = width
Création d’une méthode magique pour la représentation de chaînes
Puis, créons une méthode permettant à notre classe de générer une chaîne de caractères lisible qui représentera l’objet. Cette méthode sera appelée chaque fois que nous invoquerons la fonction str() en passant une instance de la classe Rectangle en tant qu’argument. Elle sera également sollicitée lorsque nous appellerons des fonctions qui requièrent un argument de type chaîne, comme la fonction d’impression.
class Rectangle: def __init__(self, height, width): self.height = height self.width = width def __str__(self): return f'Rectangle({self.height}, {self.width})'
La méthode __str__() doit retourner une chaîne qui, selon vous, représente l’objet. Dans ce cas, nous renvoyons une chaîne au format Rectangle(
Création de méthodes magiques pour les opérations de comparaison
Nous allons maintenant créer des opérateurs de comparaison pour les opérations d’égalité, d’infériorité et de supériorité. C’est ce que l’on appelle la surcharge d’opérateur. Pour cela, nous utilisons respectivement les méthodes magiques __eq__, __lt__ et __gt__. Ces méthodes retourneront une valeur booléenne après avoir comparé les aires des rectangles.
class Rectangle: def __init__(self, height, width): self.height = height self.width = width def __str__(self): return f'Rectangle({self.height}, {self.width})' def __eq__(self, other): """ Checking for equality """ return self.height * self.width == other.height * other.width def __lt__(self, other): """ Checking if the rectangle is less than the other one """ return self.height * self.width < other.height * other.width def __gt__(self, other): """ Checking if the rectage is greater than the other one """ return self.height * self.width > other.height * other.width
Comme vous pouvez le constater, ces méthodes prennent deux paramètres en compte. Le premier est le rectangle actuel et le second est l’autre valeur avec laquelle il est comparé. Cette valeur peut être une autre instance de Rectangle ou toute autre valeur. La logique de la comparaison et les conditions qui détermineront si la comparaison retourne vrai dépendent entièrement de vous.
Méthodes magiques courantes
Dans cette partie, nous allons aborder les méthodes magiques que vous rencontrerez et utiliserez le plus souvent.
#1. Opérations arithmétiques
Les méthodes magiques arithmétiques sont invoquées lorsqu’une instance de votre classe est placée à gauche d’un opérateur arithmétique. La méthode sera appelée avec deux arguments : le premier est une référence à l’instance ; la deuxième valeur est l’objet situé à droite de l’opérateur. Voici les méthodes et les opérateurs concernés :
Nom | Méthode | Opérateur | Description |
Addition | __add__ | + | Implémentation de l’addition |
Soustraction | __sub__ | – | Implémentation de la soustraction |
Multiplication | __mul__ | * | Implémentation de la multiplication |
Division | __div__ | / | Implémentation de la division |
Division entière | __floordiv__ | // | Implémentation de la division entière |
#2. Opérations de comparaison
Tout comme les méthodes magiques arithmétiques, ces méthodes sont sollicitées lorsqu’une instance de la classe pour laquelle elles sont définies est placée à gauche de l’opérateur de comparaison. Elles sont également appelées avec deux paramètres : le premier est une référence à l’instance de l’objet ; le second est une référence à la valeur située à droite de l’opérateur.
Nom | Méthode | Opérateur | Description |
Inférieur à | __lt__ | < | Implémente la comparaison « inférieur à » |
Supérieur à | __gt__ | > | Implémente la comparaison « supérieur à » |
Égal à | __eq__ | == | Implémente la comparaison « égal à » |
Inférieur ou égal à | __le__ | <= | Implémente la comparaison « inférieur ou égal à » |
Supérieur ou égal à | __ge__ | >= | Implémente la comparaison « supérieur ou égal à » |
#3. Opérations de cycle de vie
Ces méthodes sont appelées lors des différentes étapes du cycle de vie d’un objet, comme l’instanciation ou la suppression. Le constructeur, __init__, appartient à cette catégorie. Voici les méthodes courantes de cette catégorie :
Nom | Méthode | Description |
Constructeur | __init__ | Cette méthode est appelée à chaque fois qu’un objet de la classe pour laquelle elle est définie est créé. |
Suppression | __del__ | Cette méthode est appelée à chaque fois qu’un objet de la classe pour laquelle elle est définie est sur le point d’être supprimé. Elle peut servir à effectuer des actions de nettoyage, comme la fermeture des fichiers ouverts. |
Nouveau | __new__ | La méthode __new__ est appelée en premier lorsqu’un objet de la classe spécifiée est instancié. Cette méthode est invoquée avant le constructeur et reçoit la classe ainsi que tous les arguments supplémentaires. Elle retourne une instance de la classe. Bien que peu utile dans la plupart des cas, elle est abordée en détail ici. |
#4. Opérations de représentation
Nom | Méthode | Description |
Str | __str__ | Retourne une représentation sous forme de chaîne de caractères lisible de l’objet. Cette méthode est invoquée lors de l’appel de la fonction str(), en passant une instance de la classe en tant qu’argument. Elle est également sollicitée lorsque vous passez l’instance aux fonctions print() et format(). Elle a pour but de fournir une chaîne compréhensible par l’utilisateur final de l’application. |
Repr | __repr__ | Retourne une représentation sous forme de chaîne de caractères de l’objet destinée au développeur. Idéalement, la chaîne retournée doit être riche en informations afin qu’il soit possible de reconstruire une instance identique de l’objet à partir de cette seule chaîne. |
Meilleures pratiques pour créer des méthodes magiques
Les méthodes magiques sont d’une grande utilité et peuvent simplifier votre code. Cependant, il est important de tenir compte des points suivants lorsque vous les utilisez.
- Utilisez-les avec modération : l’implémentation d’un trop grand nombre de méthodes magiques dans vos classes peut rendre votre code difficile à comprendre. Limitez-vous aux méthodes qui sont indispensables.
- Assurez-vous de bien comprendre les implications en termes de performances des méthodes telles que __setattr__ et __getattr__ avant de les utiliser.
- Documentez précisément le comportement de vos méthodes magiques, afin que les autres développeurs sachent exactement ce qu’elles font. Cela facilitera leur utilisation et leur débogage en cas de besoin.
Derniers mots
Dans cet article, j’ai présenté les méthodes magiques comme un moyen de créer des classes pouvant être utilisées avec des opérations intégrées. J’ai également expliqué comment elles sont définies et j’ai montré un exemple de classe implémentée avec des méthodes magiques. Ensuite, j’ai mentionné les différentes méthodes que vous serez amené à rencontrer et que vous utiliserez probablement, avant de partager quelques bonnes pratiques à suivre.
Ensuite, vous pourriez être intéressé par la manière d’implémenter la classe Counter en Python.