介绍
要让自定义类支持 | 运算,需要在类中实现 __or__ 方法
如果还想支持 反向运算,比如 3 | 自定义对象,还需要实现 __ror__
方法说明
__or__(self, other):定义self | other的行为__ror__(self, other):定义other | self的行为(当other不支持| self时触发)
案例
假设我们有一个 购物车类,想通过 | 运算符实现 两个购物车的水果合并(合并规则:保留所有水果,数量取两者中的最大值),这比位或的原生含义更贴合日常认知。
定义类
class FruitCart:
"""水果购物车类"""
def __init__(self, fruits=None):
# 初始化购物车,默认空字典(水果名: 数量)
self.fruits = fruits if fruits is not None else {}
def __repr__(self):
# 自定义打印格式,方便查看结果
return f"购物车:{self.fruits}"
# 核心:自定义 | 运算符,实现两个购物车合并
def __or__(self, other):
# 第一步:检查右侧是否也是 FruitCart 实例(类型校验)
if not isinstance(other, FruitCart):
raise TypeError("| 运算符右侧必须是 FruitCart 实例!")
# 第二步:创建新购物车,用于存储合并结果
merged_fruits = {}
# 第三步:合并当前购物车的水果
for fruit, count in self.fruits.items():
merged_fruits[fruit] = count
# 第四步:合并另一个购物车的水果(数量取最大值)
for fruit, count in other.fruits.items():
if fruit in merged_fruits:
# 如果水果已存在,数量取两者中更大的
merged_fruits[fruit] = max(merged_fruits[fruit], count)
else:
# 水果不存在,直接添加
merged_fruits[fruit] = count
# 第五步:返回新的合并后购物车
return FruitCart(merged_fruits)
执行
# 测试自定义 | 运算符
if __name__ == "__main__":
# 创建两个购物车
cart1 = FruitCart({"苹果": 2, "香蕉": 3})
cart2 = FruitCart({"香蕉": 5, "橙子": 4})
# 使用 | 运算符合并购物车(核心:触发 __or__ 方法)
merged_cart = cart1 | cart2
# 打印结果
print("购物车1:", cart1)
print("购物车2:", cart2)
print("合并后:", merged_cart)
运行结果
购物车1: 购物车:{'苹果': 2, '香蕉': 3}
购物车2: 购物车:{'香蕉': 5, '橙子': 4}
合并后: 购物车:{'苹果': 2, '香蕉': 5, '橙子': 4}
代码逐行解释
- 类初始化
__init__:接收一个水果字典(键:水果名,值:数量),默认空字典,方便创建空购物车; - 打印格式
__repr__:自定义打印时的显示效果,避免输出默认的内存地址,更直观; - 核心方法
__or__:- 先校验右侧对象类型,避免和非购物车对象错误运算;
- 创建新字典存储合并结果,保证原购物车不被修改(符合 Python 不可变设计的直觉);
- 先把第一个购物车的水果加入新字典;
- 遍历第二个购物车的水果:已存在的水果取数量最大值,不存在的直接添加;
- 返回新的
FruitCart实例,作为合并结果。
案例拓展:支持多购物车连续合并
因为 __or__ 返回的是 FruitCart 实例,所以可以像 cart1 | cart2 | cart3 这样连续合并:
# 新增第三个购物车
cart3 = FruitCart({"橙子": 2, "葡萄": 1})
# 连续合并
total_cart = cart1 | cart2 | cart3
print("连续合并后:", total_cart)
# 输出:连续合并后:购物车:{'苹果': 2, '香蕉': 5, '橙子': 4, '葡萄': 1}
注意事项
- 语义合理性:重载运算符时要符合直觉,比如
|通常用于「管道/合并」类逻辑,不要滥用(比如用|做减法); - 类型检查:一定要在
__or__中检查other的类型,避免和其他类型错误运算; - 返回值:可以返回新实例、可调用对象(如示例中的 Chain),根据需求设计。
总结
- Python 支持通过实现
__or__魔法方法自定义|运算符的行为,这是运算符重载的核心; - 自定义时建议做好类型检查,保证运算符语义符合直觉(如管道、合并);