Python魔法揭秘:特殊名称与内置功能的"暗号"对照表
一、引言:揭开"魔法"的面纱
当你写下 len(my_list) 或 my_obj + 1 时,Python 是如何知道怎么做的?
答案是一套约定俗成的"暗号"系统——特殊名称(Magic Methods)。它们是 Python 对象与解释器之间的通信协议,以双下划线开头和结尾(因此也叫 Dunder Methods,Double UNDERscore)。
掌握这些暗号,你就能让自定义对象像内置类型一样工作。
二、基础篇:对象的"自我介绍"与"生命周期"
2.1 对应关系
| 特殊名称 | 对应的内置功能 | 说明 |
|---|---|---|
__init__ |
对象初始化 | 构造函数,创建实例时调用 |
__str__ |
str() / print() |
面向用户的友好展示 |
__repr__ |
repr() / 交互式显示 |
面向开发者的精确描述 |
2.2 代码演示
1 | class Person: |
在交互式命令行中直接输入 p,显示的是 __repr__ 的结果;print(p) 调用的是 __str__。
三、进阶篇:让对象像数字一样运算
3.1 对应关系
| 特殊名称 | 对应的操作符 | 说明 |
|---|---|---|
__add__ |
+ |
加法 |
__sub__ |
- |
减法 |
__mul__ |
* |
乘法 |
__truediv__ |
/ |
除法 |
__floordiv__ |
// |
整除 |
__mod__ |
% |
取模 |
__pow__ |
** |
幂运算 |
__eq__ |
== |
等于 |
__lt__ |
< |
小于 |
__le__ |
<= |
小于等于 |
__gt__ |
> |
大于 |
__ge__ |
>= |
大于等于 |
__ne__ |
!= |
不等于 |
3.2 代码演示
1 | class Vector: |
当你写 v1 + v2 时,Python 实际上调用的是 v1.__add__(v2)。操作符只是语法糖,魔法方法才是真正的执行者。
四、高阶篇:让对象像容器一样工作
4.1 对应关系
| 特殊名称 | 对应的内置功能 | 说明 |
|---|---|---|
__len__ |
len() |
获取长度 |
__getitem__ |
obj[key] |
索引访问 |
__setitem__ |
obj[key] = value |
索引赋值 |
__delitem__ |
del obj[key] |
索引删除 |
__contains__ |
x in obj |
成员检测 |
__iter__ |
for x in obj |
迭代协议 |
__next__ |
next() |
迭代器协议 |
4.2 代码演示
1 | class CustomList: |
实现了 __len__ 和 __getitem__,你的对象就能被 len() 度量和被索引访问。实现了 __iter__,就能被 for 循环遍历。这就是 Python 的**协议(Protocol)**思想——不需要继承特定基类,只要实现了对应的方法,就拥有了对应的能力。
五、属性访问的"守门员"
5.1 对应关系
| 特殊名称 | 触发时机 | 说明 |
|---|---|---|
__getattr__ |
访问不存在的属性 | 兜底机制 |
__getattribute__ |
访问任何属性 | 拦截所有属性访问 |
__setattr__ |
设置任何属性 | 拦截赋值操作 |
__delattr__ |
删除属性 | 拦截删除操作 |
5.2 代码演示
1 | class ReadOnly: |
__getattr__ 只在属性不存在时被调用(兜底),而 __getattribute__ 在每次属性访问时都被调用(更强大但也更危险,容易导致无限递归)。
六、完整对照表
| 特殊名称 | 对应的内置功能 | 分类 |
|---|---|---|
__init__ |
对象初始化 | 生命周期 |
__str__ |
str() / print() |
字符串表示 |
__repr__ |
repr() |
字符串表示 |
__add__ |
+ |
算术运算 |
__sub__ |
- |
算术运算 |
__mul__ |
* |
算术运算 |
__eq__ |
== |
比较运算 |
__lt__ |
< |
比较运算 |
__len__ |
len() |
容器协议 |
__getitem__ |
obj[key] |
容器协议 |
__setitem__ |
obj[key] = val |
容器协议 |
__contains__ |
x in obj |
容器协议 |
__iter__ |
for x in obj |
迭代协议 |
__next__ |
next() |
迭代协议 |
__getattr__ |
访问不存在的属性 | 属性访问 |
__setattr__ |
设置属性 | 属性访问 |
__call__ |
obj() |
可调用对象 |
__enter__ / __exit__ |
with 语句 |
上下文管理 |
__hash__ |
hash() |
哈希协议 |
七、最佳实践
- 不要过度使用魔法方法——保持代码可读性,只在需要自定义行为时实现
- 优先实现
__repr__——它是最基础的调试工具,也是容器打印的默认选择 - 实现容器类型时务必遵循迭代协议——
__iter__+__next__或__getitem__ - 算术运算注意反向方法——
__radd__等方法处理1 + obj的情况 __getattr__和__getattribute__不要混淆——前者是兜底,后者是全拦截
魔法方法的本质是协议——Python 不关心你的类继承自谁,只关心你是否实现了对应的方法。这种"鸭子类型"的设计哲学,正是 Python 灵活性的根源。
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.

