Using __add__ operator with multiple arguments in Python

28,663

Solution 1

No, you can't use multiple arguments. Python executes each + operator separately, the two + operators are distinct expressions.

For your example, object + 1 + 2 really is (object + 1) + 2. If (object + 1) produces an object that has an __add__ method, then Python will call that method for the second operator.

You could, for example, return another instance of A here:

>>> class A:
...     def __init__(self, val):
...         self.val = val
...     def __repr__(self):
...         return f'<A({self.val})>'
...     def __add__(self, other):
...         print(f'Summing {self} + {other}')
...         return A(self.val + other)
...
>>> A(42) + 10
Summing A(42) + 10
<A(52)>
>>> A(42) + 10 + 100
Summing A(42) + 10
Summing A(52) + 100
<A(152)>

Solution 2

You would want your return value to be an object itself, that also supports the add operation, e.g.:

class A:
    def __init__(self, value=0):
        self.value = value

    def __add__(self, b):
        return A(self.value + b)

    def __str__(self):
        return str(self.value)

a = A()
print(a + 1 + 2)

Output:

3

Solution 3

It perfectly works even with multiple values since each add only adds two values (see the multiple + signs when you ad multiple values):

class A:
    def __init__(self, value):
        self.a = value
    def __add__(self, another_value):
        return self.a + another_value


a = A(1)
print(a+1+1)

Solution 4

you could always just do this:

>>> class A:
...     def __init__(self, val):
...         self.val = val
...     def __repr__(self):
...         return f'<A({self.val})>'
...     def __add__(self, other):
...         print(f'Summing {self} + {other}')
...         return A(self.val + other)
...
>>> A(42) + 10
Summing A(42) + 10
<A(52)>
>>> A(42) + 10 + 100
Summing A(42) + 10
Summing A(52) + 100
<A(152)>>>> class A:
...     def __init__(self, val):
...         self.val = val
...     def __repr__(self):
...         return f'<A({self.val})>'
...     def __add__(self, other):
...         print(f'Summing {self} + {other}')
...         return A(self.val + other)
...
>>> A(42) + 10
Summing A(42) + 10
<A(52)>
>>> A(42) + 10 + 100
Summing A(42) + 10
Summing A(52) + 100
<A(152)>
Share:
28,663
smith1453
Author by

smith1453

Updated on July 05, 2022

Comments

  • smith1453
    smith1453 almost 2 years

    I am trying to add a class object with a number, but I'm confused on how to go about adding a class object with two numbers. For example, this is my hypothetical add class method:

    class A:
        def __add__(self, b):
            return something
    

    I know how to add this so far:

    a = A()
    print(a + 1)
    

    But, what if I want to add it like this?

    a = A()
    print(a + 1 + 2)
    

    Should I use *args for the add class method?

  • de1
    de1 over 6 years
    In this case the last add operation is not handled by the A class anymore but is a simple addition of 2 (returned by A.__add__) and 1.
  • N M
    N M over 6 years
    Shouldn't an implemetation of radd also be added here? Also, in the case of 1 + 2 + 3, is the implementation (1.__add__(2)).__add__(3) or 1.__add__(2.__add__(3))?
  • mrCarnivore
    mrCarnivore over 6 years
    Yes you are right, but since 1 and 2 are numbers this is what should happen. If the author wanted to add two class instances then the example would not have been a+1 but a+b (a and b being instances of A)...
  • Martijn Pieters
    Martijn Pieters over 6 years
    @NM: That's not a requirement, not to answer the question at any rate.
  • Martijn Pieters
    Martijn Pieters over 6 years
    @NM: and __radd__ is only going to be called if the LHS refused to handle the operation or if the RHS is a subclass of the LHS type. 1 + 2 + 3 is (1).__add__(2).__add__(3).
  • Martijn Pieters
    Martijn Pieters over 6 years
    @NM: to word it differently, for LHS + RHS, for not issubclass(type(RHS), type(LHS)), LHS.__add__(RHS) is called first, and if that doesn't exist or returns NotImplemented only then is RHS.__radd__(LHS) tried. The subclass exception is there to make it possible to subclass existing types and 'capture' the operator hook.
  • ThatOneAmazingPanda
    ThatOneAmazingPanda over 3 years
    does this help?