CodeGym /Cours /Python SELF FR /Surcharge d'opérateurs

Surcharge d'opérateurs

Python SELF FR
Niveau 20 , Leçon 0
Disponible

6.1 Méthodes magiques

La surcharge d'opérateurs en Python te permet de définir ou modifier le comportement des opérateurs intégrés (comme +, -, *, /) pour les classes personnalisées. Cela se fait à l'aide de méthodes spéciales, également appelées méthodes magiques.

Par exemple, dans ta classe, tu peux surcharger les opérateurs de comparaison :

Opérateur Méthode sans underscore Signature de la méthode
== eq() __eq__(self, other)
!= ne() __ne__(self, other)
< lt() __lt__(self, other)
<= le() __le__(self, other)
> gt() __gt__(self, other)
>= ge() __ge__(self, other)

Supposons que tu as écrit ta classe et que tu souhaites que les objets de ta classe soient comparés comme tu le souhaites. Tu dois simplement implémenter la méthode «__eq__» dans ta classe, et Python l'appellera chaque fois que des objets de ta classe seront comparés dans le code.

Exemple :


class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
        
# Utilisation
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1 == v2)  # Affichera: True
print(v1 == v3)  # Affichera: False

Chaque fois que tu compares deux de tes objets, Python vérifie s'il n'y a pas une fonction «__eq__» implémentée. Si elle existe, il l'appelle. Sinon, il comparera simplement les références des objets.

En fait, dans l'exemple ci-dessus, c'est comme si on écrivait (il faut juste ajouter la vérification de l'existence de la méthode) :


# Utilisation
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1.__eq__(v2))  # Affichera: True
print(v1.__eq__(v3))  # Affichera: False

6.2 Liste de tous les opérateurs

Il existe 6 groupes d'opérateurs disponibles pour la surcharge.

Opérateurs arithmétiques :

Opérateur Méthode sans underscore Signature de la méthode
+ add __add__(self, other)
- sub __sub__(self, other)
* mul __mul__(self, other)
/ truediv __truediv__(self, other)
// floordiv __floordiv__(self, other)
% mod __mod__(self, other)
** pow __pow__(self, other)

Opérateurs de comparaison :

Opérateur Méthode sans underscore Signature de la méthode
== eq __eq__(self, other)
!= ne __ne__(self, other)
< lt __lt__(self, other)
<= le __le__(self, other)
> gt __gt__(self, other)
>= ge __ge__(self, other)

Opérateurs logiques :

Opérateur Méthode sans underscore Signature de la méthode
& and __and__(self, other)
| or __or__(self, other)
^ xor __xor__(self, other)
~ invert __invert__(self)

Opérateurs d'indexation et de découpage :

Opérateur Méthode
obj[key] __getitem__(self, key)
obj[key] = value __setitem__(self, key, value)
del obj[key] __delitem__(self, key)

Opérateurs unaires :

Opérateur Méthode
- __neg__(self)
+ __pos__(self)
abs() __abs__(self)
~ __invert__(self)

Opérateurs d'affectation :

Opérateur Méthode
+= __iadd__(self, other)
-= __isub__(self, other)
*= __imul__(self, other)
/= __itruediv__(self, other)
//= __ifloordiv__(self, other)
%= __imod__(self, other)
**= __ipow__(self, other)

Peut-être que c'est pour ça que Python est si lent - à chaque fois avant d'exécuter un opérateur, il cherche une fonction équivalente dans la classe et tous ses parents. Mais cela permet d'écrire le code le plus compact au monde :)

6.3 Opérateur d'indexation

Le fait que l'on puisse comparer des objets ou soustraire des ensembles semble quelque peu évident. Et tu le devineras toi-même si tu écris une classe qui implique sur elle des opérations logiques ou mathématiques.

Je veux te montrer un exemple intéressant - comme l'opérateur d'indexation. Commençons directement avec le code de l'exemple :


class CustomList:
    def __init__(self, data):
        self.data = data
        
    def __getitem__(self, index):
        return self.data[index]
        
    def __setitem__(self, index, value):
        self.data[index] = value
        
    def __delitem__(self, index):
        del self.data[index]
        
    def __repr__(self):
        return repr(self.data)
        
# Utilisation
c_list = CustomList([1, 2, 3, 4, 5])
print(c_list[1])  # Affichera: 2
c_list[1] = 10
print(c_list)  # Affichera: [1, 10, 3, 4, 5]
del c_list[1]
print(c_list)  # Affichera: [1, 3, 4, 5]

Ici, nous voyons un exemple de trois opérations :

  • Lecture de données par index
  • Écriture de données par index
  • Et même suppression de données par index.

Et il n'est pas du tout nécessaire que les données soient stockées sous forme de liste à l'intérieur. Ou l'index ne doit pas nécessairement être un nombre. Par exemple, la classe dictionary (dictionnaire) est implémentée exactement ainsi.

Créons SuperList

Tu te souviens de la classe list? On peut y attribuer des éléments, mais seulement avec les indices qui existent déjà. Faisons notre propre classe, appelons-la SuperList, à laquelle on peut accéder pour chaque élément à n'importe quel index :

  • Si l'index < 0, nous insérons l'élément au début
  • Si l'index >= len, nous ajoutons l'élément à la fin
  • Dans les autres cas, nous retournons simplement l'élément

Exemple :


class SuperList(list):
    def __init__(self, value):
        super().__init__(value)
        
    def __setitem__(self, index, value):
        if index >= len(self):
            super().append(value)
        elif index < 0:
            super().insert(0, value)
        else:
            super().__setitem__(index, value)
        
lst = SuperList([1, 2, 3])
lst[200] = 100
lst[-200] = 99
print(lst)  # [99, 1, 2, 3, 100]

Donc, la surcharge des index est une opportunité géniale, et je te recommande de l'utiliser en pratique. C'est tout pour aujourd'hui.

Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION