__add__

Qu'est-ce que la méthode spéciale add en Python ?

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'
PYTHON
Un instant

Créez un compte pour exécuter ce code

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'])
PYTHON
Un instant

Créez un compte pour exécuter ce code

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'
PYTHON
Un instant

Créez un compte pour exécuter ce code

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'
PYTHON
Un instant

Créez un compte pour exécuter ce code

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
PYTHON
Un instant

Créez un compte pour exécuter ce code

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é.

Bravo, tu es prêt à passer à la suite

Rechercher sur le site

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.