1

我有一个名为MyData已定义的类(__mul__以及__rmul__所有其他算术运算符)。每当使用这些方法时,它应该总是返回一个 type 的值MyData。但是,我发现这a * myDataObj与. 具体来说,如果是 a ,它工作得很好,但是如果是 a那么第一个配置返回一个数组(我的对象有一个 numpy 数组作为成员,并返回该数组的切片),第二个配置返回 type 的正确值。myDataObj * aaaintafloatMyData.__getitem__MyData

有没有办法在这样的表达式中确定运算符的调用顺序?

4

1 回答 1

5

有没有办法在这样的表达式中确定运算符的调用顺序?

首先,语言参考的数据模型部分描述了确切的规则,特别是“模拟数字类型”小节。

方法描述__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不是intor的子类floatint也不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>
于 2013-08-15T20:52:39.370 回答