I am currently trying to understand where the difference between using
def __add__(self, other):
print("C.__add__", self, other)
def __radd__(self, other):
print("C.__radd__", self, other)
return "reversed result"
c = C()
C.__radd__ <C object at 0x7f60b92e9550> 1
Based on the docs on "special" methods:
__add__()is called to implement the binary arithmetic "+" operation. For instance, to evaluate the expression x + y, where x is an instance of a class that has an
If one of those methods does not support the operation with the supplied arguments, it should return NotImplemented.
These functions are only called if the left operand does not support the corresponding operation and the operands are of different types. For instance, to evaluate the expression x + y, where y is an instance of a class that has an
y.__radd__(x)is called if
If the right operand’s type is a subclass of the left operand’s type and that subclass provides the reflected method for the operation, this method will be called before the left operand’s non-reflected method. This behavior allows subclasses to override their ancestors’ operations.
Explanation with the examples based on the behaviour:
>>> print 1+c ('C.__radd__', <__main__.C instance at 0x7ff5631397a0>, 1) reversed result
radd are only called if the left operand does not support the corresponding operation and the operands are of different types. In this case,
1 does not support addition of the class hence, it falls back to the
__radd__() function of the
C class. In case
__radd__ was not implement in
C() class, it would have fallen back to
>>> 1 .__add__(c) NotImplemented >>> c .__add__(1) ('C.__add__', <__main__.C instance at 0x7ff563139830>, 1) 'result'
1 .__add__(c) gives
1 is of
int type and
int class do not supports
add with C class object. But
c .__add(1) run because
C() class supports that.
>>> int.__add__(1, c) NotImplemented >>> C.__add__(c, 1) ('C.__add__', <__main__.C instance at 0x7ff5610add40>, 1) 'result'
case 2. But here, the call is made via class with first argument as object of that class. Behaviour would be same.
>>> int.__add__(c, 1) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: descriptor '__add__' requires a 'int' object but received a 'instance' >>> C.__add__(1, c) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method __add__() must be called with C instance as first argument (got int instance instead)
case 3. As is cleared from the stack-trace,
__add__ expected the object of the calling class as the first argument, failing which resulted in exception.