Python类通过定义__and__和__or__方法实现&和|运算符重载,需显式返回非None值(如新实例),否则if obj1 & obj2会因None无__bool__而报错;支持链式运算要求每次返回同类实例。

Python类怎么实现&和|运算符重载
直接在类中定义 __and__ 和 __or__ 方法即可,这两个是 Python 内置的“反射方法”(dunder method),对应 & 和 | 二元操作符。调用时 Python 自动触发,不需要手动调用。
注意:仅当左操作数是该类实例时,__and__ / __or__ 才会被调用;如果左操作数不支持,且右操作数实现了对应的 __rand__ / __ror__,才可能回退调用——但多数自定义场景只需实现左边版本。
-
__and__(self, other):必须返回一个值,不能只写逻辑不 return,否则默认返回None,导致表达式结果为None - 参数
other类型不做限制,可做类型检查(比如只接受同类型或 int),也可宽松处理 - 若想支持链式运算(如
a & b & c),每个__and__返回值也得是同类实例,否则后续&会失败
为什么__and__返回None会导致bool()报错
常见错误现象:if obj1 & obj2: 报 TypeError: __bool__ returned non-bool (type NoneType)。这是因为 __and__ 没有显式 return,隐式返回 None,而 if 语句需要对结果调用 __bool__ 或 __len__,但 None 不支持这些协议。
- 务必在
__and__/__or__中 return 一个有明确真值的对象(如新实例、int、bool) - 不要只写
self.flag &= other.flag就结束——这行代码本身不产生返回值 - 若逻辑上只需“就地修改”,也应显式
return self(前提是允许原地变更)
实际例子:用位运算模拟权限组合
假设你有一个 Permission 类,内部用整数存储权限位,希望支持 p1 & p2(取交集)、p1 | p2(取并集):
立即学习“Python免费学习笔记(深入)”;
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
class Permission:
def __init__(self, bits=0):
self.bits = bits & 0xFF # 限制为8位
<pre class="brush:php;toolbar:false;">def __and__(self, other):
if not isinstance(other, Permission):
return NotImplemented
return Permission(self.bits & other.bits)
def __or__(self, other):
if not isinstance(other, Permission):
return NotImplemented
return Permission(self.bits | other.bits)
def __repr__(self):
return f"Permission({self.bits:#010b})"
这样就能写 read | write 或 admin & user,返回仍是 Permission 实例,可继续参与运算。
- 返回
NotImplemented而非抛异常,让 Python 尝试调用other.__rand__等回退逻辑,更符合 Python 惯例 - 用
& 0xFF截断高位,避免无意义的符号扩展(尤其在右移或取反后) - 不建议在
__and__中直接修改self.bits并return self,除非你明确要“可变权限对象”,否则易引发共享状态问题
和内置整数位运算行为一致吗
不完全一致。Python 整数的 & / | 是纯函数式、不可变的,且对任意整数都成立;而你自定义的类只在显式定义了对应方法时才支持,且行为完全由你控制。
- 整数支持
1 & 2 & 4是因为int.__and__返回新int,你的类也要保持同样契约 - 整数还支持与布尔值运算(
1 & True→1),但你的类若没处理bool类型,就会走到NotImplemented分支,最终报TypeError - 如果你的类实例被用于集合(
set)或字典键,还需额外实现__hash__和__eq__,否则无法去重或查找
真正容易被忽略的是:位运算重载不是“语法糖”,它不改变底层数据表示,也不自动提供掩码、测试某位等辅助逻辑——那些都得你自己基于 self.bits 手动实现。

















