Reflected dunder 方法不适用于相同类型的实例

Reflected dunder method doesn't work for instances of the same type

这是一个小的重现 - class A 和 B 完全相同,为反射右移运算符实现了 dunder 方法。因此,x >> y 有望解析为 y.__rrshift__(x)

class A:
    def __init__(self, x):
        self.x = x
        
    def __rrshift__(self, other):
        return self.__class__(self.x + other.x)

class B:
    def __init__(self, x):
        self.x = x
        
    def __rrshift__(self, other):
        return self.__class__(self.x + other.x)

但是,dunder 方法不适用于相同 class 的实例。

A(1) >> A(2)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for >>: 'A' and 'A'

虽然它适用于来自不同 classes 的实例。

A(1) >> B(2)

<__main__.B object at 0x7f6ca8294f40>

这真是令人惊讶。并且似乎也是其他反映运算符的常见行为(例如 radd)。这是行不通的原因吗?

doc states一样,操作数不同类型时有效

These functions are only called if the left operand does not support the corresponding operation and the operands are of different types


看来你只需要 __rshift__ 两个 类 (只有 A 对你的例子有效)

def __rshift__(self, other):
    return self.__class__(self.x + other.x)

来自文档(Python 语言参考手册中的 3.3.8. Emulating numeric types 部分):

These functions are only called if the left operand does not support the corresponding operation [3] and the operands are of different types. [4]

其中 footnote 4 显示:

[4] For operands of the same type, it is assumed that if the non-reflected method – such as __add__() – fails then the overall operation is not supported, which is why the reflected method is not called.

因此,无论喜欢与否,该行为都是有意为之并记录在案的。