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.