本文参考《流畅的 Python》(Fluent Python)一书,深入讲解 Python 的数据模型(Data Model),帮助你理解 Python 中"魔法方法"的本质与威力。
什么是数据模型? Python 的数据模型(Data Model)是语言的核心设计之一。它定义了对象如何与语言的各种特性交互——比如迭代、比较、运算符重载、属性访问等。这些交互通过特殊方法 (Special Methods,俗称"魔法方法"或"dunder methods",即双下划线方法)来实现。
核心思想 :Python 的数据模型让自定义对象能够像内置类型一样自然地工作。当你实现了这些特殊方法,你的对象就获得了与内置类型相同的能力。
特殊方法的本质 特殊方法以双下划线开头和结尾,例如 __init__、__len__、__getitem__ 等。它们不是为直接调用而设计的,而是被 Python 解释器在特定场景下自动调用。
1 2 3 4 5 obj.__len__()len (obj)
这种设计体现了 Python 的一致性 :内置类型和用户自定义类型使用相同的接口。
六大核心类别 1. 对象初始化与销毁 方法 触发时机 说明 __new__(cls, ...)创建实例时 控制实例创建,很少需要重写 __init__(self, ...)实例初始化时 最常见的初始化方法 __del__(self)实例被垃圾回收时 析构方法,慎用
1 2 3 4 5 6 7 8 9 10 11 12 class Vector : def __new__ (cls, *components ): print (f"Creating instance of {cls.__name__} " ) return super ().__new__(cls) def __init__ (self, *components ): self ._components = components def __del__ (self ): print (f"Destroying {self} " )
2. 字符串表示 方法 触发方式 用途 __repr__(self)repr(obj)开发者调试,应尽可能精确 __str__(self)str(obj) / print()面向用户的友好表示 __format__(self, fmt)format(obj, fmt)格式化输出 __bytes__(self)bytes(obj)字节表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Vector : def __init__ (self, x, y ): self .x = x self .y = y def __repr__ (self ): return f"Vector({self.x!r} , {self.y!r} )" def __str__ (self ): return f"({self.x} , {self.y} )" def __format__ (self, fmt ): if fmt == "polar" : import math r = math.hypot(self .x, self .y) theta = math.atan2(self .y, self .x) return f"(r={r:.2 f} , θ={math.degrees(theta):.1 f} °)" return str (self ) v = Vector(3 , 4 )print (repr (v)) print (str (v)) print (f"{v:polar} " )
3. 集合类协议(容器与序列) 这是 Python 数据模型中最强大的部分之一。实现这些方法,你的对象就能像 list、dict、set 一样工作。
方法 触发方式 说明 __len__(self)len(obj)返回元素数量 __getitem__(self, key)obj[key]按索引或键获取 __setitem__(self, key, value)obj[key] = value设置元素 __delitem__(self, key)del obj[key]删除元素 __contains__(self, item)item in obj成员检查 __iter__(self)iter(obj) / for迭代器 __reversed__(self)reversed(obj)反向迭代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from typing import Iteratorclass Vector : def __init__ (self, *components ): self ._components = components def __len__ (self ) -> int : return len (self ._components) def __getitem__ (self, index ): if isinstance (index, slice ): return Vector(*self ._components[index]) return self ._components[index] def __iter__ (self ) -> Iterator[float ]: return iter (self ._components) def __contains__ (self, item ) -> bool : return item in self ._components def __reversed__ (self ): return Vector(*reversed (self ._components)) v = Vector(1.0 , 2.0 , 3.0 , 4.0 )print (len (v)) print (v[1 ]) print (v[1 :3 ]) print (2.0 in v) print (list (reversed (v)))
4. 数值类型协议 让你的对象支持数学运算。
方法 触发方式 说明 __add__, __radd__a + b加法 __sub__, __rsub__a - b减法 __mul__, __rmul__a * b乘法 __truediv__a / b真除法 __floordiv__a // b地板除 __mod__a % b取模 __pow__a ** b幂运算 __neg__-a取负 __abs__abs(a)绝对值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Vector : def __init__ (self, x, y ): self .x = x self .y = y def __add__ (self, other ): if isinstance (other, Vector): return Vector(self .x + other.x, self .y + other.y) return NotImplemented def __radd__ (self, other ): return self .__add__(other) def __mul__ (self, scalar ): if isinstance (scalar, (int , float )): return Vector(self .x * scalar, self .y * scalar) return NotImplemented def __rmul__ (self, scalar ): return self .__mul__(scalar) def __neg__ (self ): return Vector(-self .x, -self .y) def __abs__ (self ): import math return math.hypot(self .x, self .y) def __repr__ (self ): return f"Vector({self.x} , {self.y} )" v1 = Vector(1 , 2 ) v2 = Vector(3 , 4 )print (v1 + v2) print (v1 * 3 ) print (3 * v1) print (-v1) print (abs (v1))
5. 比较与哈希 方法 触发方式 说明 __eq__a == b相等比较 __ne__a != b不等比较 __lt__a < b小于 __le__a <= b小于等于 __gt__a > b大于 __ge__a >= b大于等于 __hash__hash(obj)哈希值,用于 dict/set
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 from functools import total_ordering@total_ordering class Vector : def __init__ (self, x, y ): self .x = x self .y = y def __eq__ (self, other ): if not isinstance (other, Vector): return NotImplemented return (self .x, self .y) == (other.x, other.y) def __lt__ (self, other ): if not isinstance (other, Vector): return NotImplemented return abs (self ) < abs (other) def __hash__ (self ): return hash ((self .x, self .y)) def __abs__ (self ): import math return math.hypot(self .x, self .y) v1 = Vector(1 , 2 ) v2 = Vector(3 , 4 ) v3 = Vector(1 , 2 )print (v1 == v3) print (v1 < v2) print (v1 <= v3) mapping = {v1: "point A" }print (mapping[v3])
6. 上下文管理器协议 方法 触发方式 说明 __enter__with 语句进入时返回上下文对象 __exit__with 语句退出时处理异常清理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from typing import Optional import timeclass Timer : """计时器上下文管理器""" def __enter__ (self ): self .start = time.perf_counter() return self def __exit__ (self, exc_type, exc_val, exc_tb ) -> Optional [bool ]: self .end = time.perf_counter() self .elapsed = self .end - self .start print (f"耗时: {self.elapsed:.4 f} 秒" ) return None with Timer() as t: time.sleep(0.1 )
可调用对象 通过 __call__ 方法,让对象可以像函数一样被调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from typing import Callable class Average : """计算移动平均""" def __init__ (self ): self ._items = [] def __call__ (self, value: float ) -> float : self ._items.append(value) return sum (self ._items) / len (self ._items) def __repr__ (self ): return f"Average({self._items!r} )" avg = Average()print (avg(10 )) print (avg(20 )) print (avg(30 ))
属性描述符(进阶) 描述符是 Python 数据模型中更高级的特性,用于控制属性访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 from typing import Any class Validator : """验证属性值的描述符""" def __init__ (self, min_value: float , max_value: float ): self .min_value = min_value self .max_value = max_value self .name = "" def __set_name__ (self, owner, name ): self .name = name def __get__ (self, instance, owner ): if instance is None : return self return instance.__dict__[self .name] def __set__ (self, instance, value: Any ): if not self .min_value <= value <= self .max_value: raise ValueError( f"{self.name} 必须在 [{self.min_value} , {self.max_value} ] 之间," f"得到 {value} " ) instance.__dict__[self .name] = valueclass Person : age = Validator(0 , 150 ) score = Validator(0 , 100 ) def __init__ (self, age: int , score: float ): self .age = age self .score = score p = Person(25 , 88.5 ) p.age = 30
数据模型的设计哲学 《流畅的 Python》一书强调,Python 数据模型的核心设计哲学是:
协议驱动 :Python 不强制继承,而是通过实现协议(一组特殊方法)来获得能力。这被称为"鸭子类型"的极致体现。
一致性 :内置类型和用户自定义类型使用相同的接口。len() 对 list、str 和你自己的类都有效。
最小惊讶原则 :实现特殊方法后,对象的行为应该符合直觉。+ 应该表示"合并"或"相加",而不是其他含义。
组合优于继承 :通过实现协议,你可以让类获得多种能力,而不需要复杂的继承层次。
完整示例:自定义序列类型 下面是一个完整的自定义序列类型,展示了数据模型的实际应用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 from typing import Iterator, Iterable, TypeVar, Generic T = TypeVar("T" )class SortedList (Generic [T]): """保持排序的列表""" def __init__ (self, initial: Iterable[T] = ( ) ): self ._items: list [T] = sorted (initial) def __len__ (self ) -> int : return len (self ._items) def __getitem__ (self, index: int | slice ) -> T | "SortedList[T]" : if isinstance (index, slice ): return SortedList(self ._items[index]) return self ._items[index] def __setitem__ (self, index: int , value: T ) -> None : self ._items[index] = value self ._items.sort() def __delitem__ (self, index: int ) -> None : del self ._items[index] def __iter__ (self ) -> Iterator[T]: return iter (self ._items) def __reversed__ (self ) -> Iterator[T]: return reversed (self ._items) def __contains__ (self, item: T ) -> bool : import bisect index = bisect.bisect_left(self ._items, item) return index != len (self ._items) and self ._items[index] == item def __repr__ (self ) -> str : return f"SortedList({self._items!r} )" def add (self, item: T ) -> None : """添加元素,保持有序""" import bisect bisect.insort(self ._items, item) def index (self, item: T ) -> int : """查找元素位置""" import bisect index = bisect.bisect_left(self ._items, item) if index != len (self ._items) and self ._items[index] == item: return index raise ValueError(f"{item!r} not in list" ) sl = SortedList([3 , 1 , 4 , 1 , 5 , 9 , 2 , 6 ])print (sl) print (len (sl)) print (sl[3 ]) print (5 in sl) print (list (sl)) sl.add(7 )print (sl)
总结 Python 的数据模型是理解这门语言的关键。通过掌握特殊方法,你可以:
让自定义对象像内置类型一样工作 写出更 Pythonic、更直观的代码 利用协议而非继承来扩展功能 创建与其他 Python 代码无缝集成的库 《流畅的 Python》一书将这些概念称为"Python 风格的对象"。当你真正理解了数据模型,你就能写出既优雅又强大的 Python 代码。
参考