学习Python的__rshift__()函数

418 阅读1分钟

语法

object.__rshift__(self, other)

Python__rshift__() 方法实现了内置的>> 操作。因此,当你调用x >> y 时,Python 会尝试调用x.__rshift__(y) 。如果这个方法没有实现,Python首先尝试在右边的操作数上调用__rrshift__ ,如果这个方法也没有实现,它就会引发一个TypeError

我们把这称为 "Dunder Method",即*"Double UnderscoreMethod"(也称为"Magic Method")*。

背景rshift()

Python的 位向右移操作符x >> n ,将整数x 的二进制表示法向右移动n

它在左边插入一个0 位,并删除最右边的位。例如,如果你将二进制表示0101 右移一个位置,你会得到0010 。从语义上讲,位右移操作与进行整数除以2**n 是一样的。

print(8 << 1)
# 16

print(8 << 2)
# 32

print(-3 << 1)
# -6

自定义__lshift__()示例

在下面的例子中,你创建了一个自定义类Data ,并重写了__lshift__() 方法,以便在试图计算位数左移操作时返回一个假字符串。

class Data:
        
    def __lshift__(self, other):
        return '... my result of lshift...'


a = Data()
b = Data()

print(a << b)
# ... my result of lshift...

如果你没有定义__lshift__() 方法,Python 会提出一个TypeError

TypeError: <<的操作数类型不支持

考虑下面的代码片段,你试图在没有定义dunder方法的情况下计算自定义对象的左移操作__lshift__()

class Data:
    pass


a = Data()
b = Data()

print(a << b)

在我的电脑上运行这个导致了以下错误信息。

Traceback (most recent call last):
  File "C:UsersxcentDesktopcode.py", line 8, in <module>
    print(a << b)
TypeError: unsupported operand type(s) for <<: 'Data' and 'Data'

这个错误的原因是,__lshift__() 方法从来没有被定义过--而且默认情况下没有为自定义对象定义该方法。所以,为了解决TypeError: unsupported operand type(s) for << ,你需要在你的类定义中提供__lshift__(self, other) 方法,如前所示。

class Data:
        
    def __lshift__(self, other):
        return '... my result of lshift...'

当然,在实践中你会使用另一个返回值,正如在**"Background lshift() "**部分所解释的。

Python 的 __lshift__ 与 __rlshift__ 的比较

假设,你想在两个自定义对象xy 上计算左移的操作。

print(x << y)

Python 首先尝试调用左边对象的__lshift__() 方法x.__lshift__(y) 。但这可能因为两个原因而失败。

  1. 方法x.__lshift__() 首先没有实现,或者
  2. 方法x.__lshift__() 已经实现,但是返回一个NotImplemented 值,表明数据类型不兼容。

如果失败了,Python 试图通过调用y.__rlshift__() 对右操作数进行反向左移来 解决这个问题y 。并不是说这与>运算符">右移不一样,它只是意味着在第二个操作数上调用左移操作y

如果实现了反向左移的方法,Python 知道它不会遇到非交换性操作的潜在问题。如果它只是执行y.__lshift__(x) 而不是x.__lshift__(y) ,结果就会是错误的,因为这个操作是非交换性的。这就是为什么需要y.__rlshift__(x)

因此,x.__lshift__(y)x.__rlshift__(y) 之间的区别是,前者计算x << y 而后者计算y << x - 两者都调用定义在对象x 上的各自方法。

你可以在这里看到这个效果,我们试图在左边的操作数x 上调用这个操作,但是由于它没有实现,Python 只是在右边的操作数y 上调用相反的操作。

class Data_1:
    pass

class Data_2:
    def __rlshift__(self, other):
        return 'called reverse lshift'


x = Data_1()
y = Data_2()

print(x << y)
# called reverse lshift