Python数据模型的核心是协议,即通过实现特定方法(如__len__、__getitem__等)使对象支持对应操作;常用协议包括__init__/__new__、__str__/__repr__、__eq__/__hash__、__contains__,且协议间存在隐含约束。

理解Python数据模型的核心:对象协议
Python的数据模型是一套定义对象如何与语言交互的规则,其核心是“协议”——不是接口或抽象类,而是一组约定俗成的方法名和行为规范。只要对象实现了特定方法(如 __len__、__getitem__、__add__),它就自动支持对应操作(len()、下标访问、+运算)。这种设计让自定义类型能自然融入Python生态,无需继承特定基类。
常用协议方法及其触发场景
掌握几个高频协议方法,就能显著提升类的可用性:
- __init__ 和 __new__:分别控制实例初始化和对象创建,__new__ 是真正的构造器,常用于单例、不可变类型定制
-
__str__ 与 __repr__:前者面向用户,返回易读字符串;后者面向开发者,应尽量可执行(如
eval(repr(obj)) == obj) - __eq__ 和 __hash__:一起实现才能让对象可比较、可放入集合或字典;若重写了 __eq__ 但没定义 __hash__,对象默认变为不可哈希
-
__contains__:让
in操作符生效;若未实现,Python会退回到遍历 __iter__ 或尝试 __getitem__
用协议实现自然的行为定制
行为定制不是靠条件判断,而是靠协议方法的有机组合。例如,要让一个序列类支持切片、迭代和成员检测:
- 实现 __getitem__:既支持
obj[i],也自动支持obj[start:stop]和for x in obj:(只要索引越界时抛 IndexError) - 补充 __len__:让
len(obj)可用,并使 __getitem__ 中的切片逻辑更健壮 - 定义 __contains__:避免默认的线性搜索,可基于内部结构(如已排序列表用二分查找)加速
x in obj
注意协议间的隐含约束
协议不是孤立的,某些方法之间存在逻辑依赖。忽略这些容易引发意外行为:
- 若支持可变序列操作(如
append),通常应同时实现 __iadd__(+=)而非仅依赖 __add__,否则+=会创建新对象,违背原地修改预期 - 实现 __bool__ 时,除非有明确语义,否则不要返回随机值;Python在
if obj:中优先调用它,若未定义则回退到 __len__(非零即真) - 自定义 __getattr__ 要谨慎:它只在属性查找失败时触发;若想拦截所有访问,需用 __getattribute__,但它会影响性能且易引发无限递归










