Python类通过实现__and__和__or__方法支持&和|操作符,左操作数优先调用对应方法;若返回NotImplemented,才尝试右操作数的__rand__或__ror__,否则直接报错。

Python类怎么支持&和|操作符
直接重写实例的 __and__ 和 __or__ 方法即可,Python在遇到 a & b 时会尝试调用 a.__and__(b),不是调用 b.__rand__(a)(除非 a.__and__ 返回 NotImplemented)。这点和算术运算不同,位运算的左操作数优先级更高。
常见错误是只实现了 __and__ 却没处理右操作数为其他类型的情况,导致 int & MyObj 失败——这时候 Python 不会自动调用 MyObj.__rand__,而是直接报 TypeError,除非你显式实现 __rand__ 和 __ror__。
-
__and__(self, other):处理self & other,返回新实例或原地修改后返回self(推荐返回新对象) -
__or__(self, other):同理,对应self | other - 若希望支持
other & self(如1 & obj),必须额外实现__rand__(self, other) - 返回
NotImplemented而非抛异常,才能触发反向方法或回退到默认逻辑
为什么__and__返回NotImplemented后没走__rand__
因为 Python 只有在左操作数的 __and__ 明确返回 NotImplemented 时,才尝试右操作数的 __rand__。如果抛了 TypeError 或其他异常,就直接中断了。
典型陷阱:在 __and__ 里写了 if not isinstance(other, MyType): raise TypeError(...) ——这会让 1 & obj 直接崩,而不是交由 obj.__rand__(1) 处理。
- 正确做法是:
if not isinstance(other, MyType): return NotImplemented -
__rand__的参数顺序是(self, other),其中other是原始左操作数(即1 & obj中的1) -
__rand__和__ror__通常用于支持内置类型在左、自定义类型在右的场景
实际例子:一个支持位运算的权限标志类
假设你有一个 Permission 类,内部用整数存标志位,想让它能和 int、其他 Permission 实例做 & 和 |:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
class Permission:
def __init__(self, value: int):
self.value = value & 0xFFFF # 限制16位
<pre class="brush:php;toolbar:false;">def __and__(self, other):
if isinstance(other, Permission):
return Permission(self.value & other.value)
elif isinstance(other, int):
return Permission(self.value & other)
return NotImplemented
def __rand__(self, other):
if isinstance(other, int):
return Permission(other & self.value)
return NotImplemented
def __or__(self, other):
if isinstance(other, Permission):
return Permission(self.value | other.value)
elif isinstance(other, int):
return Permission(self.value | other)
return NotImplemented
def __ror__(self, other):
if isinstance(other, int):
return Permission(other | self.value)
return NotImplemented
这样就能安全混用:perm & 4、8 | perm、perm1 & perm2 都成立。
性能与兼容性要注意什么
位运算符重载本身开销极小,但要注意返回值类型一致性:如果 __and__ 有时返回 Permission,有时返回 int 或 None,下游代码容易出错。建议始终返回同类实例。
- 避免在
__and__中修改self(即不要原地更新self.value),否则违反位运算的不可变直觉 - Python 3.10+ 对
__and__等方法做了少量优化,但行为没变;旧版本也完全兼容 - 如果类还参与集合运算(如放进
set),记得同时实现__hash__和__eq__,否则可能被当作不同对象
最易忽略的一点:很多人以为只要实现 __and__ 就能支持所有位运算组合,其实 ^(异或)、~(取反)、/>> 都要单独实现对应方法,它们之间不互相推导。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










