Python 特殊方法
说明 Python 特殊方法如何把对象接入运算符、容器、迭代器、上下文管理器等语言级协议。
#type / concept
#status / growing
#resource / python
#tech / lang / python
[!info] related notes
- 所属 MOC: Python 类与面向对象 MOC
- 前置概念: python类属性与实例属性, python实例方法类方法与静态方法
- 并列概念: Python 多重继承与 MRO
- 易混淆概念: 鸭子类型
- 关系笔记: python类与面向对象
Python 特殊方法
一句话定义
特殊方法是形如 __xxx__ 的协议钩子,Python 解释器会在运算符、内建函数或特定语法场景下自动调用它们,从而让自定义对象表现得像内建类型一样自然。
核心机制 / 工作原理
1. 特殊方法的本质是“语言协议入口”
当你写:
len(obj)obj1 + obj2for x in objwith obj as resource
Python 并不是在做魔法,而是在尝试调用对象对应的特殊方法,例如:
__len____add____iter____enter__/__exit__
所以特殊方法的价值在于:让你的对象接入 Python 的统一调用协议。
2. 常见协议大致可以分成几类
- 构造与表示:
__new__、__init__、__repr__ - 容器与迭代:
__len__、__getitem__、__iter__ - 运算符:
__add__、__eq__ - 可调用对象:
__call__ - 上下文管理:
__enter__、__exit__
你不需要一次记完所有名字,但要先建立一个观念:这些不是零散技巧,而是 Python 数据模型的一部分。
3. 特殊方法让“对象行为”能被统一消费
如果一个对象实现了 __iter__,它就能被 for 循环消费;如果实现了 __len__,它就能被 len() 读取长度。也就是说,调用方往往不关心“你是不是某个具体类”,只关心“你有没有协议要求的行为”。
这也正好和 鸭子类型 的思路衔接起来。
最小例子 / 最小场景
class Vector:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __repr__(self):
return f"Vector({self.x}, {self.y})"
def __len__(self):
return int((self.x ** 2 + self.y ** 2) ** 0.5)
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
print(len(v1)) # 2
这里同一个类同时接入了“加法协议”“字符串表示协议”“长度协议”。
边界与易混淆点
- 不是所有双下划线名字都能随便自创;只有 Python 约定好的协议名才会被解释器识别。
- 特殊方法通常应该通过语法或内建函数触发,例如用
len(obj)而不是直接手写obj.__len__()。 - 特殊方法应该服务于对象语义,而不是为了“看起来高级”把普通业务逻辑硬塞进 dunder 方法里。