Surcharge des opérateurs en Python
La surcharge d’opérateurs vous permet de redéfinir la signification d’opérateur en fonction de votre classe. C’est la magie de la surcharge d’opérateurs que nous avons pu utiliser l’opérateur + pour ajouter deux objets numériques, ainsi que pour concaténer deux objets chaîne.
Cette fonctionnalité en Python, qui permet à un même opérateur d’avoir une signification différente en fonction du contexte, est appelée surcharge d’opérateur.
Alors que se passe-t-il lorsque nous les utilisons avec des objets d'une classe définie par l'utilisateur ? Considérons la classe suivante :
Exemple 1 :
class Point: def __init__(self, x, y): self.x = x self.y = y p1 = Point(2, 4) p2 = Point(5, 1) p3 = p1+p2
File "prog.py", line 10, in < module>
p3 = p1+p2
TypeError: unsupported operand type(s) for +: 'Point' and 'Point'
TypeError a été généré car Python ne savait pas comment ajouter deux objets Point ensemble.
Cependant, la bonne nouvelle est que nous pouvons apprendre cela à Python en surchargeant les opérateurs. Mais tout d’abord, parlons des fonctions spéciales.
La surcharge de l'opérateur est obtenue en définissant une méthode spéciale dans la définition de classe. Les noms de ces méthodes commencent et finissent par un double soulignement (__).
Opérateurs arithmétiques
Opérateur +
Pour surcharger l'opérateur +, nous devrons implémenter la fonction __add __ () dans la classe. Un grand pouvoir implique de grandes responsabilités. Nous pouvons faire ce que nous voulons, dans cette fonction.
Exemple 2 :
class Point: def __init__(self, x, y): self.x = x self.y = y def __str__(self): return "({0},{1})".format(self.x, self.y) def __add__(self, p): a = self.x + p.x b = self.y + p.y return Point(a, b) p1 = Point(2, 4) p2 = Point(5, 1) p3 = p1+p2 print(p3)
Si l'expression est de la forme x + y, Python l'interprète comme x .__ add __ (y). La version de la méthode __add __ () appelée dépend du type de x et de y.
Fonctions spéciales de surcharge de l'opérateur en Python
Le tableau suivant répertorie les opérateurs et leur méthode spéciale correspondante.
Operateur | Expression | Interprétation Python |
---|---|---|
Addition | p1 + p2 | p1.__add__(p2) |
Soustration | p1 - p2 | p1.__sub__(p2) |
Multiplication | p1 * p2 | p1.__mul__(p2) |
Puissance | p1 ** p2 | p1.__pow__(p2) |
Division | p1 / p2 | p1.__truediv__(p2) |
Division entière | p1 // p2 | p1.__floordiv__(p2) |
le reste (modulo) | p1 % p2 | p1.__mod__(p2) |
Décalage binaire gauche | p1 << p2 | p1.__lshift__(p2) |
Décalage binaire droite | p1 >> p2 | p1.__rshift__(p2) |
ET binaire | p1 & p2 | p1.__and__(p2) |
OU binaire | p1 | p2 | p1.__or__(p2) |
XOR | p1 ^ p2 | p1.__xor__(p2) |
NON binaire | ~p1 | p1.__invert__() |
Surcharge des opérateurs de comparaison
Python ne limite pas la surcharge des opérateurs aux seuls opérateurs arithmétiques. Nous pouvons également surcharger les opérateurs de comparaison.
Supposons que nous voulions implémenter le symbole inférieur à < dans notre classe Point.
Comparons la magnitude de ces points depuis l'origine et retournons le résultat. Il peut être implémenté comme suit.
Exemple 3 :
import math class Point: def __init__(self, x, y): self.x = x self.y = y def __lt__(self, p): m_self = math.sqrt((self.x ** 2) + (self.y ** 2)) m2_p = math.sqrt((p.x ** 2) + (p.y ** 2)) return m_self < m2_p p1 = Point(2, 4) p2 = Point(5, 1) if p1 < p2: print("p2 est plus loin que p1")
De même, les fonctions spéciales que nous devons implémenter pour surcharger d’autres opérateurs de comparaison sont résumées ci-dessous.
Operateur | Expression | Interprétation Python |
---|---|---|
Inférieur à | p1 < p2 | p1.__lt__(p2) |
Inférieur ou égal | p1 <= p2 | p1.__le__(p2) |
Egal | p1 == p2 | p1.__eq__(p2) |
différent | p1 != p2 | p1.__ne__(p2) |
Supérieur à | p1 > p2 | p1.__gt__(p2) |
Supérieur ou égal | p1 >= p2 | p1.__ge__(p2) |
Exemple 4 :
import math class Point: def __init__(self, x=0, y=0): self.__x = x self.__y = y # Opérateur + def __add__(self, p): return Point(self.__x + p.__x, self.__y + p.__y) # Opérateur - def __sub__(self, p): return Point(self.__x - p.__x, self.__y - p.__y) # Opérateur < def __lt__(self, p): m_self = math.sqrt((self.__x ** 2) + (self.__y ** 2)) m_p = math.sqrt((p.__x ** 2) + (p.__y ** 2)) return m_self < m_p # Opérateur <= def __le__(self, p): m_self = math.sqrt((self.__x ** 2) + (self.__y ** 2)) m_p = math.sqrt((p.__x ** 2) + (p.__y ** 2)) return m_self <= m_p # Opérateur > def __gt__(self, p): m_self = math.sqrt((self.__x ** 2) + (self.__y ** 2)) m_p = math.sqrt((p.__x ** 2) + (p.__y ** 2)) return m_self > m_p # Opérateur >= def __ge__(self, p): m_self = math.sqrt((self.__x ** 2) + (self.__y ** 2)) m_p = math.sqrt((p.__x ** 2) + (p.__y ** 2)) return m_self >= m_p # Opérateur == def __eq__(self, p): m_self = math.sqrt((self.__x ** 2) + (self.__y ** 2)) m_p = math.sqrt((p.__x ** 2) + (p.__y ** 2)) return m_self == m_p