学习Python的__or__()方法

164 阅读3分钟

语法

object.__or__(self, other)

Python__or__() 方法实现了内置的 Bitwise OR&| 操作。因此,当你调用x & y 时,Python 会尝试调用x.__and__(y) 。如果这个方法没有实现,Python首先尝试在右边的操作数上调用__rand__ ,如果这个方法也没有实现,就会引发一个TypeError

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

背景 位数和与

Python的 ***位数和*操作符x & y 在整数xy 的二进制表示上的每个位上执行逻辑 AND。因此,如果同一位置的两个输入位都是1,则每个输出位都是1,否则就是0。例如,整数表达式4 & 3被翻译成二进制的0100 & 0011,结果是0000,因为所有四个输入位的位置都不同。

在这个例子中,你将 位数和 操作符到两个整数32和16。

>>> 32 & 16
0

表达式32 & 16 对位表示法"010000" (十进制 32)和"001000" (十进制 16)进行操作,并执行 位数与.由于所有第i个位的位置都不同,结果是0。

第一个操作数x100000
第二个操作数y010000
x & y000000

例子 自定义__和__()

在下面的例子中,你创建了一个自定义类Data 并覆盖了__and__() 方法,这样当试图计算位数与运算时,它就会返回一个假字符串。

class Data:
        
    def __and__(self, other):
        return '... my result of AND ...'


a = Data()
b = Data()

print(a & b)
# ... my result of AND ...

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

TypeError:&的操作数类型不支持。

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

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'

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

class Data:
        
    def __and__(self, other):
        return '... my result of AND ...'

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

Python的__and__与__rand__的比较

假设,你想对两个自定义对象xy 进行& 的计算。

print(x & y)

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

  1. 该方法x.__and__() 首先没有实现,或者
  2. 该方法 x.__`and`__()实现了,但返回一个NotImplemented ,表明数据类型不兼容。

如果失败了,Python 试图通过调用右操作数y.__rand__()反向位智和 方法来解决这个问题y

如果反向位数与方法被实现了,Python 知道它不会遇到非交换性操作的潜在问题。如果它只是执行y.__and__(x) 而不是x.__and__(y) ,结果将是错误的,因为当定义为自定义操作时,该操作可能是非交换性的。这就是为什么需要y.__rand__(x)

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

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

class Data_1:
    pass

class Data_2:
    def __rand__(self, other):
        return 'called reverse bitwise AND'


x = Data_1()
y = Data_2()

print(x & y)
# called reverse bitwise AND