拒绝死记硬背!用 C++ 的底层逻辑,彻底搞懂 Python 的“魔术方法”
一、引言:打破“魔法”的迷信
初学者看到 __init__、__str__ 这种双下划线方法就头大,只能死记硬背。但对于C++程序员来说,这些其实就是编译器在特定时刻自动调用的“钩子函数”。
二、核心类比
- Python 的
obj + obj对应 C++ 的operator+重载 - Python 的
str(obj)对应 C++ 的operator std::string()或toString()虚函数 - Python 的
cls对应 C++ 的static类作用域
三、变身术:类型转换协议 (str vs int)
1. __str__ (人类视图)
- C++ 类比:相当于 C++ 中重载
std::ostream& operator<<(std::ostream&, const T&) - 触发时机:当你执行
print(obj)或str(obj)时 - 用途:返回一个人类可读的字符串
2. __repr__ (机器视图)
- C++ 类比:相当于调试器中显示对象的逻辑
- 触发时机:当你在交互式终端中直接输入对象名并回车时
- 用途:返回一个能被
eval()重建对象的字符串
四、算术与增量运算协议
1. 基本运算
__add__:对应+运算符__sub__:对应-运算符__mul__:对应*运算符__truediv__:对应/运算符
2. 反向运算
__radd__:当a + b中a不支持+操作时,会尝试b.__radd__(a)
3. 增量运算
__iadd__:对应+=运算符,比+更高效
五、比较运算协议
__eq__:对应==运算符__lt__:对应<运算符__gt__:对应>运算符__le__:对应<=运算符__ge__:对应>=运算符__ne__:对应!=运算符
技巧:Python 有个 @total_ordering 装饰器,只要你定义了 __eq__ 和一个比较符(如 __lt__),它会自动补全其他的(类似 C++ 的 std::rel_ops)
六、容器与布尔协议:Python 特有的“真值测试”
1. __len__
- C++ 类比:相当于类的
.size()或.length()成员函数 - 触发时机:当你调用
len(obj)时
2. __bool__
- C++ 类比:相当于 C++ 的
explicit operator bool() - 触发时机:当你执行
if obj:时 - 注意:如果没有定义这个,Python 会退而求其次调用
__len__(如果长度为 0 则为 False)
七、容器协议
__getitem__:对应obj[key]读取操作__setitem__:对应obj[key] = value赋值操作__iter__:让对象变成可迭代对象__next__:实现迭代器协议
八、代码实战:Vector 类
1 | from functools import total_ordering |
九、总结:从“语法糖”到“协议”
C++ 的操作符重载是静态绑定的(编译期决定),而 Python 的魔术方法是动态派发的(运行时查找)。
不要死记硬背这些方法名,而是记住场景:
- 想打印?找
__str__ - 想相加?找
__add__ - 想比大小?找
__lt__/__gt__/__eq__ - 想变类型?找
__int__/__bool__
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.

