I have two different classes, and I want to define the addition of them only in one class, and define both __add__
and __radd__
for that class (in my example below, that's ExampleClass2
. I DO NOT want to create an __add__
method that works for ExampleClass1
to add ExampleClass2
.
As it is right now it just ignores it. I also tried with raising error, but that didn't work either.
class ExampleClass1:
def __init__(self, data):
self.data = data
def __add__(self, other):
if isinstance(other, int):
print('other was an int')
class ExampleClass2:
def __init__(self, data):
self.data = data
def __add__(self, other):
if isinstance(other, ExampleClass1):
print("it's working")
__radd__ = __add__
a = ExampleClass1('q')
b = ExampleClass2('w')
a+b
__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.
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'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With