Why does calling Python's 'magic method' not do type conversion like it would for the corresponding operator?
a - b
isn't just a.__sub__(b)
. It also tries b.__rsub__(a)
if a
can't handle the operation, and in the 1 - 2.
case, it's the float's __rsub__
that handles the operation.
>>> (2.).__rsub__(1)-1.0
You ran a.__rsub__(2.)
, but that's the wrong __rsub__
. You need the right-side operand's __rsub__
, not the left-side operand.
There is no implicit type conversion built into the subtraction operator. float.__rsub__
has to handle ints manually. If you want type conversion in your own operator implementations, you'll have to handle that manually too.
@user2357112 already said it well but there's nothing like an example.
class A: def __sub__(self, other): print('A.__sub__') if not isinstance(other, A): return NotImplemented return 0 def __rsub__(self, other): print('A.__rsub__') if not isinstance(other, A): return NotImplemented return 0class B: def __sub__(self, other): print('B.__sub__') if not isinstance(other, B): return NotImplemented return 0
a1 = A()a2 = A()b = B()a1 - a2A.__sub__# 0
Objects a1
and a2
are compatible (both type A
), a valid result is returned.
Next, consider,
b - a1B.__sub__A.__rsub__# TypeError: unsupported operand type(s) for -: 'B' and 'A'
Objects b
and a1
are not compatible. First, b.__sub__
is tried, which returns NotImplemented
, so a1.__rsub__
is tried, which also returns NotImplemented
. So a TypeError
is raised.
Finally,
a1 - bA.__sub__# TypeError: unsupported operand type(s) for -: 'A' and 'B'
This time, a1.__sub__
is tried first, which returns NotImplemented
. Now, since b.__rsub__
is not defined, a TypeError
is raised.