魔法方法是Python中以双下划线开头和结尾的特殊方法,由解释器在特定语法(如+、len()、==)触发时自动调用,用于定义类的对象行为协议,实现运算符重载、字符串表示、比较逻辑等功能。
Python 中的双下划线方法(如 __add__、__eq__、__len__)不是“魔法”,而是明确的协议接口——它们被解释器在特定语法触发时自动调用,本质上是 Python 对象模型的契约式约定。
为什么叫“魔法方法”?这名字容易误导人
“魔法”只是社区流传的俗称,源于它们不显式调用却自动生效的表象。实际没有神秘机制:当你写 a + b,CPython 就查 a.__add__(b);写 len(obj),就调 obj.__len__()。它和 list.append() 一样是普通方法,只是调用时机由语法规定。
- 名称带双下划线本身不赋予任何特殊能力,只是避免与用户定义的普通方法名冲突
- 如果类没实现
__add__,+操作直接抛TypeError: unsupported operand type(s) - 解释器不会“猜测”行为,只按文档明确定义的协议查找和调用
__add__ 和 __radd__ 必须成对考虑才能支持交换律
仅实现 __add__ 不足以让自定义类型参与所有加法场景。比如 1 + my_obj 不会调 my_obj.__add__(1),而会尝试 int.__add__(1, my_obj)(失败后才 fallback 到 my_obj.__radd__(1))。
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
-
__add__(self, other):处理self + other,即左操作数是当前实例 -
__radd__(self, other):当左操作数不支持该运算(如内置类型),且右操作数是当前实例时调用 - 若想支持
int + MyNumber和MyNumber + int,两个方法都得实现,且逻辑要一致 - 忽略
__radd__是导致“TypeError: unsupported operand type”最常见原因
运算符重载不是炫技,而是补全对象语义
重载 == 或 __eq__ 的目的,不是为了“看起来像数字”,而是让比较行为符合业务含义。比如一个表示时间区间的类,== 应该判断起止时间是否完全重合,而不是内存地址是否相同。
- 未定义
__eq__时,默认使用is(即身份比较),几乎总是错的 - 定义
__eq__后,in、set成员检测、dict键查找等都会依赖它 - 若重载了
__eq__,强烈建议也实现__hash__(除非对象可变),否则无法放入set或作dict键 -
__str__和__repr__分工明确:print()调前者(面向用户),交互式环境默认显示后者(面向开发者),混用会导致调试困难
真正容易被忽略的点在于:这些方法不是孤立存在的。一个看似简单的 == 操作,背后牵扯到哈希一致性、容器行为、序列协议甚至 pickle 序列化。写 __eq__ 时顺手补上 __hash__,写 __len__ 前先确认是否真需要支持 bool(obj) 隐式转换——这才是魔法方法落地时最常翻车的地方。