Qu'est-ce que la méthode add ?
La méthode spéciale __add__ définit le comportement de l'opérateur + sur les objets des classes que vous créez. Si vous prenez une instance a, une instance b et que vous faites a + b, en réalité, Python appelle a.__add__(b).
Sans cette méthode, Python ne saura pas additionner les objets de vos classes.
Prenons une classe Panier (il faut bien que Patrick et Sébastien puissent faire leurs courses) :
class Panier: def __init__(self, articles): self.articles = articles def __repr__(self): return f"Panier({self.articles})" panier_patrick = Panier(["pommes", "pâtes en forme de dinosaures"]) panier_sebastien = Panier(["café", "jouet licorne"]) print(panier_patrick + panier_sebastien) # TypeError: unsupported operand type(s) for +: 'Panier' and 'Panier'
Inscrivez-vous gratuitement pour modifier et exécuter du code Python directement dans votre navigateur.
Impossible de fusionner leurs paniers, et Python nous donne la raison : il n'existe pas d'opérateur + entre deux objets Panier.
À noter
La méthode __repr__ sert uniquement à afficher nos paniers de manière lisible pour nos exemples.
Comment implémenter add ?
Il suffit de définir la méthode __add__ :
class Panier: def __init__(self, articles): self.articles = articles def __repr__(self): return f"Panier({self.articles})" def __add__(self, autre): return Panier(self.articles + autre.articles) panier_patrick = Panier(["pommes", "pâtes en forme de dinosaures"]) panier_sebastien = Panier(["café", "jouet licorne"]) panier_commun = panier_patrick + panier_sebastien print(panier_commun) # Panier(['pommes', 'pâtes en forme de dinosaures', 'café', 'jouet licorne'])
Inscrivez-vous gratuitement pour modifier et exécuter du code Python directement dans votre navigateur.
__add__ ne modifie pas les objets, elle renvoie un nouvel objet Panier.
À noter
Le principe reste le même pour les autres opérateurs, comme __sub__ pour - ou __mul__ pour *.
Comment gérer les mauvais types avec add ?
Avec notre implémentation actuelle, que se passe-t-il si Patrick additionne son panier avec un autre type d'objet ?
class Panier: def __init__(self, articles): self.articles = articles def __repr__(self): return f"Panier({self.articles})" def __add__(self, autre): return Panier(self.articles + autre.articles) panier_patrick = Panier(["pommes", "pâtes en forme de dinosaures"]) print(panier_patrick + 5) # AttributeError: 'int' object has no attribute 'articles'
Inscrivez-vous gratuitement pour modifier et exécuter du code Python directement dans votre navigateur.
La bonne pratique est de vérifier le type et de renvoyer NotImplemented :
class Panier: def __init__(self, articles): self.articles = articles def __repr__(self): return f"Panier({self.articles})" def __add__(self, autre): if not isinstance(autre, Panier): return NotImplemented return Panier(self.articles + autre.articles) panier_patrick = Panier(["pommes", "pâtes en forme de dinosaures"]) print(panier_patrick + 5) # TypeError: unsupported operand type(s) for +: 'Panier' and 'int'
Inscrivez-vous gratuitement pour modifier et exécuter du code Python directement dans votre navigateur.
NotImplemented permet de dire à Python que notre classe ne sait pas faire cette addition, et Python va générer un message clair. Mais nous reviendrons sur le NotImplemented dans un glossaire dédié.
À noter
__add__ n'est appelée que lorsque votre objet est à gauche du +. S'il est à droite, c'est la méthode __radd__ qui est utilisée : par exemple pour 10 + panier_patrick.
L'opérateur +=
L'incrémentation, ou addition sur place, a sa propre méthode __iadd__, mais Python se replie sur __add__ si elle n'existe pas.
class Panier: def __init__(self, articles): self.articles = articles def __repr__(self): return f"Panier({self.articles})" def __add__(self, autre): if not isinstance(autre, Panier): return NotImplemented return Panier(self.articles + autre.articles) panier_patrick = Panier(["pommes", "pâtes en forme de dinosaures"]) panier_sebastien = Panier(["café", "jouet licorne"]) avant = panier_patrick panier_patrick += panier_sebastien print(panier_patrick) # Panier(['pommes', 'pâtes en forme de dinosaures', 'café', 'jouet licorne']) print(avant) # Panier(['pommes', 'pâtes en forme de dinosaures']) print(avant is panier_patrick) # False
Inscrivez-vous gratuitement pour modifier et exécuter du code Python directement dans votre navigateur.
panier_patrick += panier_sebastien devient panier_patrick = panier_patrick + panier_sebastien. Un nouveau Panier a été créé et assigné à la variable, l'ancien objet n'a pas bougé.