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

时间:2013-08-15 20:42:14

标签: python python-2.7 operators

我有一个名为MyData的类,其中定义了__mul____rmul__(以及所有其他算术运算符)。每当使用这些方法时,它应始终返回类型MyData的值。但是,我发现a * myDataObjmyDataObj * a不同,具体取决于a的类型。具体来说,如果aint,它工作正常,但如果afloat,那么第一个配置返回一个数组(我的对象有一个numpy数组作为成员,MyData.__getitem__返回该数组的切片),第二个配置返回类型MyData的正确值。

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

1 个答案:

答案 0 :(得分:5)

  

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

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

__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不是intfloat的子类,intfloat都不知道如何乘以它,它们都会调用{ {1}}。你抛出的任何其他不相关的类型也是如此:

Base.__rmul__
  

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

有很多原因:

  • 您的>>> 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 __mul__代码执行的操作不同。
  • 您继承自__rmul__
  • 您继承了一些在C-API级别处理浮点乘法的内置或扩展类型,并且不允许在子类中进行覆盖。
  • 您创建了一个经典类而不是新式类。
  • 你用其中一个名字输了一个错字。
  • ...