为什么调用Python的"魔术方法"不像对应的运算符那样进行类型转换?

dop*_*ler 29 python type-conversion magic-methods implicit-conversion

当我从一个整数(例如1-2.0)中减去一个浮点数时,Python会进行隐式类型转换(我认为).但是当我使用魔术方法调用我认为是相同的操作时__sub__,它突然不再存在了.

我在这里错过了什么?当我为自己的类重载运算符时,除了明确地将输入转换为我需要的任何类型之外,还有其他方法吗?

a=1
a.__sub__(2.)
# returns NotImplemented
a.__rsub__(2.)
# returns NotImplemented
# yet, of course:
a-2.
# returns -1.0
Run Code Online (Sandbox Code Playgroud)

use*_*ica 38

a - b不只是a.__sub__(b).b.__rsub__(a)如果a无法处理操作,它也会尝试,在这种1 - 2.情况下,它__rsub__是处理操作的float .

>>> (2.).__rsub__(1)
-1.0
Run Code Online (Sandbox Code Playgroud)

你跑了a.__rsub__(2.),但那是错的__rsub__.您需要右侧操作数__rsub__,而不是左侧操作数.


减法运算符中没有内置的隐式类型转换.float.__rsub__必须手动处理.如果您想在自己的运算符实现中进行类型转换,那么您也必须手动处理它.

  • 值得注意的是,问题中的调用返回的"NotImplemented"结果是尝试反向方法的信号. (9认同)
  • @doppler:让左操作数同时处理`__sub__`和`__rsub__`是没有意义的.这只是具有完全相同工作的两种方法,而右操作数将没有机会提供实现. (5认同)
  • @doppler:没有.自我.__ rsub __(其他)`如果`other`无法处理它,则调用`other - self`.调用`other .__ sub __(self)`将毫无意义.我们已经知道`其他'无法处理它. (4认同)

cs9*_*s95 8

@ user2357112已经说得很好,但没有什么比如一个例子了.

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
Run Code Online (Sandbox Code Playgroud)

a1 = A()
a2 = A()
b = B()

a1 - a2
A.__sub__
# 0
Run Code Online (Sandbox Code Playgroud)

对象a1a2兼容(均为类型A),则返回有效的结果.

接下来考虑,

b - a1
B.__sub__
A.__rsub__
# TypeError: unsupported operand type(s) for -: 'B' and 'A'
Run Code Online (Sandbox Code Playgroud)

对象ba1不兼容.首先,b.__sub__尝试,返回NotImplemented,所以a1.__rsub__尝试,也返回NotImplemented.因此TypeError提出了一个问题.

最后,

a1 - b
A.__sub__
# TypeError: unsupported operand type(s) for -: 'A' and 'B'
Run Code Online (Sandbox Code Playgroud)

这一次,a1.__sub__首先尝试,返回NotImplemented.现在,由于b.__rsub__未定义,TypeError因此引发了a .