Why does calling Python's 'magic method' not do type conversion like it would for the corresponding operator?

前端 未结 2 536
甜味超标
甜味超标 2021-01-03 18:45

When I subtract a float from an integer (e.g. 1-2.0), Python does implicit type conversion (I think). But when I call what I thought was the same operation usin

相关标签:
2条回答
  • 2021-01-03 19:13

    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.

    0 讨论(0)
  • 2021-01-03 19:13

    @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 0
    
    class B:
       def __sub__(self, other):
           print('B.__sub__')
           if not isinstance(other, B):
               return NotImplemented
           return 0
    

    a1 = A()
    a2 = A()
    b = B()
    
    a1 - a2
    A.__sub__
    # 0
    

    Objects a1 and a2 are compatible (both type A), a valid result is returned.

    Next, consider,

    b - a1
    B.__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 - b
    A.__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.

    0 讨论(0)
提交回复
热议问题