Cet article met en évidence les méthodes spéciales Python incontournables que tout programmeur Python doit connaître
Les méthodes magiques nous aident à enrichir nos applications. Elles ajoutent indirectement de la magie à notre code Python. C’est un sujet de niveau avancé pour les développeurs Python et je le recommande à tous ceux qui sont/ou ont l’intention d’utiliser le langage de programmation Python.
Les méthodes magiques nous donnent plus de contrôle sur le comportement de notre application.
Cet article vise à expliquer ce que sont les méthodes magiques et comment elles peuvent être utilisées pour construire des applications Python. Il fournira un aperçu des méthodes magiques les plus largement utilisées pour une gamme de types de données.
L’objectif d’exposer les méthodes magiques clés est pour nous de comprendre si nous voulons surcharger ces méthodes dans nos classes personnalisées pour enrichir les applications.
Les méthodes magiques rendent le langage de programmation Python extrêmement puissant
Quelles sont les méthodes magiques Python ?
Les méthodes magiques Python sont également connues sous le nom de méthodes spéciales ou méthodes dunder. Elles sont entourées de doubles traits de soulignement, par exemple __init__().
Un objet peut avoir un certain nombre de méthodes magiques.
Souvenez-vous que tout en Python est un objet, y compris une variable/fonction/classe etc. Les objets sont l’abstraction de python pour les données.
Les méthodes magiques sont utilisées pour construire et initialiser de nouveaux objets, elles nous aident à récupérer un objet comme un dictionnaire, elles sont utilisées pour supprimer un objet entre autres opérations. Elles sont utilisées lorsque l’opérateur + est invoqué, ou même lorsque nous voulons représenter un objet sous forme de chaîne de caractères.
Bien que chaque méthode en Python soit publique, la convention de codage consiste à entourer toutes les méthodes privées par des doubles traits de soulignement __<méthode>__()
Cela implique que les méthodes magiques sont destinées à être des méthodes privées. Cela signifie également que l’appelant d’un objet ne doit pas invoquer la méthode directement car la méthode est destinée à être invoquée par la classe en interne qui a la méthode magique.
Nous pouvons surcharger les méthodes magiques pour fournir notre propre fonctionnalité personnalisée.
Je vais expliquer les concepts des méthodes magiques en créant une classe personnalisée, puis je donnerai un aperçu des méthodes magiques les plus importantes dans un entier, une chaîne de caractères, une liste et un dictionnaire.
A mesure que nous progressons dans l’article, il commencera à construire une image beaucoup plus claire de la raison pour laquelle les méthodes magiques existent et comment les utiliser.
Si vous voulez comprendre le langage de programmation Python du niveau débutant au niveau avancé, alors je vous recommande vivement l’article ci-dessous :
J’aborderai le sujet des méthodes magiques en créant une classe personnalisée, puis j’expliquerai comment les méthodes magiques sont utilisées.
La valise d’utilisation pour comprendre les méthodes magiques
Dans le snippet ci-dessous, j’ai créé une classe appelée Human, puis j’ai instancié une instance de la classe Human.
Ce bout de code sera utilisé pour nous aider à comprendre les méthodes magiques.
Notez, l’id de l’objet human est de type integer, l’attribut name est de type string, la propriété addresses est de type list et la propriété maps est de type dictionary.
J’ai regroupé les méthodes magiques dans différentes sections de type de données pour faciliter la lecture. Cependant, les mêmes méthodes magiques se retrouvent dans différents types de données.
Les méthodes magiques peuvent être surchargées pour enrichir la fonctionnalité et créer une logique personnalisée qui convient le mieux aux besoins de l’entreprise.
Class:
Comprenons les méthodes magiques qui sont associées à l’objet human. Si j’exécute la méthode dir(human), elle listera toutes les fonctions et les noms d’attributs de l’objet humain.
Il y a en tout 29 méthodes/attributs qui sont associés à l’objet humain. Parmi elles, 26 sont les méthodes magiques.
C’est un nombre assez important de méthodes spéciales. Ces méthodes sont héritées du type de base de la classe Human. Par conséquent, ce sont les méthodes prédéfinies que nous pouvons utiliser/override pour enrichir les classes.
La prochaine partie de la section expliquera les méthodes magiques clés.
__delattr__
Cette méthode est appelée lorsque nous tentons de supprimer un attribut d’une classe.
Nous pouvons surcharger la fonctionnalité en implémentant la méthode dans la classe Human:
def __delattr__(self, item):
print('Deleting attribute ' + item)
return object.__delattr__(self, item)
Maintenant, chaque fois que nous tentons de supprimer un attribut, il affichera le message : Suppression d’un attribut
Il existe également la méthode __setattr__() pour attribuer une valeur à un attribut et __getattr__() pour obtenir une valeur de l’attribut.
Un cas d’utilisation de __delattr__() peut être d’empêcher des attributs particuliers d’un objet d’être supprimés ou lorsque nous voulons effectuer des actions spécifiques quand un attribut particulier est supprimé.
__dict__
Cette méthode retourne un dictionnaire qui représente l’objet. Les clés du dictionnaire sont les attributs de l’objet et les valeurs sont les valeurs des attributs.
Comme instance :
human = Human(2, 'Malik').__dict__
print(human)
Le code ci-dessus renvoie :
{‘id’ : 2, ‘name’ : ‘Malik’, ‘addresses’ : , ‘maps’ : {}}
__dir__
Nous pouvons surcharger la méthode dir() en surchargeant la méthode __dir__() de la classe. A titre d’exemple, nous pouvons supprimer les méthodes internes du résultat renvoyé par la méthode dir() :
__eq__
Cette méthode est appelée lorsque nous tentons d’effectuer l’opération ==. Considérons que deux objets humains sont égaux lorsque leur attribut id est égal même si leur nom est différent.
Nous pouvons surcharger la méthode __eq__() pour réaliser cette fonctionnalité:
def __eq__(self, other):
return self.id == other.id
Elle retournera maintenant True:
first = Human(1, 'Farhad')
second = Human(1, 'Malik')
print(first == second)
__format__
Chaque fois que nous tentons de faire string.format(), la méthode __format__() est invoquée en interne.
__ge__
En tant qu’instance, supposons qu’il existe deux objets Humains:
first = Human(1, 'Farhad')
second = Human(2, 'Malik')
Considérons également que notre projet a une règle selon laquelle un objet humain avec un Id plus grand est considéré comme plus grand que l’autre objet humain. Par conséquent, nous pouvons surcharger la méthode __gt__() et mettre en œuvre la logique personnalisée:
def __ge__(self, other):
return self.id >= other.id
Ceci renverra maintenant False parce que l’Id du deuxième objet humain est plus grand que le premier objet humain:
print(first >= second)
Returns False
Il existe également une méthode __lt__() qui est exécutée lorsque l’opérateur ≤ est effectué.
__hash__
Le hachage est utilisé pour convertir un objet en un nombre entier. Le hachage est effectué lorsque nous tentons de définir un élément dans un dictionnaire/ensemble.
Un bon algorithme de hachage entraîne un nombre plus faible de collisions de hachage. Nous pouvons fournir notre propre algorithme de hachage en surchargeant la méthode __hash__().
Partons du principe que l’id de l’objet Human est censé être unique dans notre application. L’algorithme __hash__() peut être surchargé pour retourner l’id de self.id en tant qu’entier de hachage:
def __hash__(self):
return self.id
Nous pouvons créer deux objets et les enregistrer dans une collection d’ensembles. Lorsque nous interrogeons la longueur de l’ensemble, nous nous attendrons à deux éléments dans l’ensemble parce que les deux objets ont un id différent.
first = Human(1, 'Farhad')
second = Human(2, 'Malik')
my_set = set()
print(len(my_set))
#returns 2
Si nous fixons maintenant l’id à 1 pour les deux objets et que nous répétons l’exercice, alors nous ne verrons qu’un seul élément dans l’ensemble parce que les deux objets ont la même clé de hachage car leur attribut id est le même, même si leur attribut name est différent.
first = Human(1, 'Farhad')
second = Human(1, 'Malik')
my_set = set()
print(len(my_set))
#returns 1
__init__
La méthode __init__() est exécutée lorsque nous voulons instancier une nouvelle instance d’une classe en appelant son constructeur.
En tant qu’instance, lorsque nous avons tenté d’exécuter :
human = Human(1, 'farhad')
Alors la méthode __init__() a été exécutée.
Nous pouvons surcharger la fonctionnalité et y passer nos propres arguments et comportements personnalisés également.
En tant qu’exemple, la méthode __init__() de la classe Human est :
def __init__(self, id, name, addresses=, maps={}):
self.id = id
self.name = name
self.addresses = addresses
self.maps = maps
__init_subclass__
C’est l’un des cas d’utilisation des métaclasses. Quand une classe est sous-classée et que son objet est créé alors la méthode __init_subclass__() est appelée.
Essentiellement, la méthode informe le parent qu’il a été sous-classé. Ce crochet peut alors initialiser toutes les sous-classes d’une classe donnée. Par conséquent, la méthode est utilisée pour enregistrer les sous-classes et attribuer des valeurs par défaut aux attributs sur les sous-classes. Par conséquent, il nous permet de personnaliser l’initialisation des sous-classes.
J’expliquerai comment les métaclasses fonctionnent dans mon prochain article.
__new__
Lorsque nous voulons instancier/créer une nouvelle instance d’une classe alors la méthode __new__(cls) est exécutée.
En guise d’exemple, considérons que nous voulons imprimer ‘Human creating…’ chaque fois que le constructeur Human() est appelé.
Nous pouvons surcharger la fonctionnalité de la méthode __new__(cls) comme indiqué ci-dessous:
def __new__(cls, *args, **kwargs):
print('Human creating...')
return object.__new__(cls)
En conséquence, Human creating… est imprimé lorsque nous avons tenté de créer une instance:
human = Human(1, 'Farhad', , {'London':2, 'UK':3})
__sizeof__
Cette méthode est appelée lorsque nous exécutons sys.getsizeof(). Elle renvoie la taille de l’objet en mémoire, en octets.
__str__
Il a imprimé : id=1. name=Farhad.
La fonction __str__() doit tenter de renvoyer une représentation conviviale de l’objet.
__weakref__
Cet objet __weakref__ renvoie la liste des références faibles à l’objet cible. Essentiellement, il aide le garbage collection à informer les références faibles que le référent a été collecté. Par conséquent, il empêche les objets d’accéder aux pointeurs sous-jacents.
Integer
Cela nous amène à la section suivante de l’article. Nous pouvons voir que la propriété id de l’objet human est de type int. Si nous effectuons ensuite dir() sur la propriété id et que nous filtrons les méthodes qui sont entourées de doubles soulignés, nous rencontrerons qu’il y a au total 62 méthodes magiques.
print(len(list(filter(lambda x: x.startswith('__') and x.endswith('__'), dir(human1.id)))))
Je vais expliquer ici les méthodes clés :
__add__
Cette méthode est appelée lorsque nous tentons d’additionner deux nombres.
En guise d’exemple:
human.id + 2 est identique à human.id.__add__(2)
__and__
Cette méthode est exécutée lorsque nous tentons d’utiliser l’opérateur & par exemple.g.:
return self & another_value
__bool__
Cette méthode est exécutée lorsque nous tentons d’effectuer la vérification booléenne sur un objet e.g.
self != 123
__floordiv__
Cette méthode est exécutée lorsque nous exécutons l’opérateur //.