有没有办法在这样的表达式中确定运算符的调用顺序?
首先,语言参考的数据模型部分描述了确切的规则,特别是“模拟数字类型”小节。
方法描述__rfoo__
如下:
调用这些方法来实现具有反射(交换)操作数的二进制算术运算( +
, -
, *
, /
, %
, divmod()
, pow()
, **
, <<
, >>
, &
, ^
, )。|
只有当左操作数不支持相应的操作并且操作数属于不同类型时,才会调用这些函数。[2] 例如,要计算表达式x - y
,其中y
是具有__rsub__()
方法的类的实例,y.__rsub__(x)
如果x.__sub__(y)
返回则调用NotImplemented
。
请注意,三元pow()
不会尝试调用__rpow__()
(强制规则会变得太复杂)。
注意 如果右操作数的类型是左操作数类型的子类,并且该子类为操作提供了反射方法,则该方法将在左操作数的非反射方法之前调用。此行为允许子类覆盖其祖先的操作。
将其放入 Pythonesque 伪代码中,x * y
评估如下:
if type(y) is type(x):
return x.__mul__(y)
elif type(y) is a subclass of type(x):
try y.__rmul__(x)
otherwise x.__mul__(y)
else:
try x.__mul__(y)
otherwise y.__rmul__(x)
当然,您也可以通过创建单独的类型来动态确定调用顺序,这些类型的方法只是打印它们的名称并测试它们:
class Base(object):
def __mul__(self, lhs): print('Base.mul')
def __rmul__(self, rhs): print('Base.rmul')
class Derived(Base):
def __mul__(self, lhs): print('Derived.mul')
def __rmul__(self, rhs): print('Derived.rmul')
class Unrelated(object):
def __mul__(self, lhs): print('Unrelated.mul')
def __rmul__(self, rhs): print('Unrelated.rmul')
print('Base * Base: ', end='')
Base() * Base()
for x, y in itertools.permutations((Base, Derived, Unrelated), 2):
print('{} * {}: '.format(x.__name__, y.__name__), end='')
x() * y()
那么内置类型呢?
完全相同的规则。由于Base
不是int
or的子类float
,int
也不float
知道如何乘以它,所以它们都会调用Base.__rmul__
. 你扔给它的任何其他不相关的类型也是如此:
>>> Base() * 2
Base.mul
>>> 2 * Base()
Base.rmul
>>> Base() * 2.5
Base.mul
>>> 2.5 * Base()
Base.rmul
>>> 'sdfsdfsdfds' * Base()
Base.rmul
>>> (lambda: 23) * Base()
Base.rmul
我的问题是我从 1.5 * myObj 和 myObj * 1.5 得到不同的结果
原因有很多:
- 你
__mul__
和__rmul__
代码不做同样的事情。
- 你继承自
float
.
- 您从一些在 C-API 级别处理浮点乘法的内置或扩展类型继承,并且不旨在允许子类中的覆盖。
- 您创建了一个经典类而不是一个新式类。
- 你在其中一个名字上打错了。
- …</li>