如何确定调用哪个运算符实例?

bhe*_*ilr 1 python operators python-2.7

我有一个名为MyDatahas has __mul____rmul__defined 的类(以及所有其他算术运算符).无论何时使用这些方法,它都应该返回一个类型的值MyData.但是,我发现它a * myDataObj不一样myDataObj * a,取决于它的类型a.具体来说,如果aint,它工作正常,但如果a是,float那么第一个配置返回一个数组(我的对象有一个numpy数组作为成员,并MyData.__getitem__返回该数组的切片),第二个配置返回正确的类型值MyData.

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

aba*_*ert 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)
Run Code Online (Sandbox Code Playgroud)

当然,您还可以通过创建单独的类型来动态确定调用顺序,这些类型的方法只是打印其名称并对其进行测试:

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

内置类型怎么样?

完全一样的规则.因为它既Base不是int或者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
Run Code Online (Sandbox Code Playgroud)

我的问题是我从1.5*myObj和myObj*1.5获得了不同的结果

原因有很多:

  • __mul____rmul__代码不做同样的事情.
  • 你继承自float.
  • 您从一些内置或扩展类型继承,它在C-API级别处理浮点乘法,并且不允许在子类中进行覆盖.
  • 您创建了一个经典类而不是新样式类.
  • 你在其中一个名字中输入了一个拼写错误.
  • ...