addition between classes using radd method

Suppose you are implementing a class that you want to act like a number via operator overloading. So you implement add in your class, and now expressions like myobj + 4 can work as you want and yield some result. This is because myobj + 4 is interpreted as myobj.__add__(4), and your custom method can do whatever it means to add 4 to your custom class.

However, what about an expression like 4 + myobj which is really (4).__add__(myobj)? The 4 is an instance of a Python built-in type and its add method doesn't know anything about your new type, so it will return a special value NotImplemented. (The interpreter recognizes this special value coming from add and raises a TypeError exception which kills your program, which is the behavior you'd actually see, rather than the special value being returned.)

It would suck for operator overloading if myobj + 4 was valid but 4 + myobj was invalid. That's arbitrary and restrictive — addition is supposed to be commutative. Enter __radd__. Python will first try (4).__add__(myobj), and if that returns NotImplemented Python will check if the right-hand operand implements radd, and if it does, it will call myobj.__radd__(4) rather than raising a TypeError. And now everything can proceed as usual, as your class can handle the case and implement your behavior, rather than the built-in type's add which is fixed and doesn't know about your class.

Example:

class X:
    
    def __init__(self, num):
        self.num = num

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

    def __add__(self, other):
        return self.num + other.num
    
    __radd__ = __add__


class Y:

    def __init__(self, num):
        self.num = num

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


x = X(5)
y = Y(10)

print(x+y)

print(y+x)

These functions __radd__ are only called if the left operand does not support the corresponding operation and the operands are of different types. For example,

class X:
  def __init__(self, num):
    self.num = num

class Y:
  def __init__(self, num):
    self.num = num

  def __radd__(self, other_obj):
    return Y(self.num+other_obj.num)

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

>>> x = X(2)
>>> y = Y(3)
>>> print(x+y)
5
>>>
>>> print(y+x)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-60-9d7469decd6e> in <module>()
----> 1 print(y+x)

TypeError: unsupported operand type(s) for +: 'Y' and 'X'

__radd__ is only called if the left object does not have an __add__ method, or that method does not know how to add the two objects (which it flags by returning NotImplemented). Both classes have an __add__ method, which do not return NotImplemented. Therefore the __radd__ method would never be called.

Tags:

Python 3.X