本文档解释了 CPython 的核心对象模型,重点介绍了基础的 PyObject 结构及其之上的类型系统。它涵盖了 Python 对象在内存中的表示方式、类型如何定义对象行为以及引用计数系统如何管理内存。有关内存分配和垃圾回收的信息,请参阅 垃圾回收。
Python 的“万物皆对象”设计理念通过一个称为 PyObject 的通用基准结构来实现。所有 Python 对象都包含此基准结构,它提供了包括引用计数和类型信息在内的关键元数据。
PyObject 结构是 Python 对象系统的基础,为所有对象提供核心元数据。
在带有 GIL 的标准构建中,PyObject 具有此基本结构。
可变大小的对象(如列表和元组)通过 PyVarObject 结构添加了 ob_size 字段。
来源
在无 GIL 线程构建中(定义了 Py_GIL_DISABLED),对象结构被扩展以支持线程安全的引用计数。
此结构通过 ob_ref_local 字段(用于拥有对象的线程)和原子 ob_ref_shared 字段(用于来自其他线程的引用)来实现每个线程的引用计数。
来源
Python 使用引用计数进行内存管理。每个对象都有一个指向它的引用计数,当该计数降至零时,对象将被释放。
Py_INCREF 和 Py_DECREF 宏是管理引用计数的首要机制。这些宏在标准构建和无 GIL 线程构建之间有所不同。
| 宏 | 标准构建 | 无 GIL 线程构建 |
|---|---|---|
Py_INCREF(op) | 递增 op->ob_refcnt | 特定于线程的本地或共享引用计数递增 |
Py_DECREF(op) | 递减 op->ob_refcnt 并调用 dealloc(如果为零) | 特定于线程的递减,可能涉及释放 |
Py_XINCREF(op) | 安全版本,会检查 NULL | 特定于线程的安全递增 |
Py_XDECREF(op) | 安全版本,会检查 NULL | 特定于线程的安全递减 |
引用计数系统还对“不朽”对象(如小的整数、None、True、False)进行了特殊处理,这些对象永远不会被释放。它们的引用计数被设置为一个特殊值。
来源
Python 的类型系统通过一个称为 PyTypeObject 的丰富结构来定义对象行为。每个 Python 对象都有一个指向其类型对象的指针,该对象定义了可对该对象执行的所有操作。
PyTypeObject 结构很复杂,包含许多定义该类型对象行为的字段。
这些字段可分为几类:
来源
类型系统使用标志(tp_flags)来控制各种功能。
| 标志 | 目的 |
|---|---|
Py_TPFLAGS_HEAPTYPE | 类型对象可以被垃圾回收 |
Py_TPFLAGS_BASETYPE | 类型可以被继承 |
Py_TPFLAGS_READY | 类型已准备好使用 |
Py_TPFLAGS_READYING | 类型正在初始化中 |
Py_TPFLAGS_HAVE_GC | 实例由 GC 跟踪 |
Py_TPFLAGS_DISALLOW_INSTANTIATION | 类型不能被实例化 |
Py_TPFLAGS_IMMUTABLETYPE | 类型在创建后不能被修改 |
来源
创建类型时,它会经历一个复杂的初始化过程,以设置所有必需的字段和关系。
PyType_Ready 函数通过初始化所有未设置的字段、设置继承和计算方法解析顺序来准备类型供使用。
来源
方法解析顺序决定了在查找属性时搜索基类的顺序。Python 使用 C3 线性化算法来计算一致的 MRO。
来源
Python 有两类类型:静态(内置)类型和堆类型(用户定义类)。
| 特征 | 静态类型 | 堆类型 |
|---|---|---|
| 内存位置 | 静态分配 | 在堆上分配 |
| 垃圾回收 | 不被 GC 跟踪 | 被 GC 跟踪 |
| 可被继承 | 如果设置了 BASETYPE 标志 | 始终 |
| 可被修改 | 否 | 是 |
| 创建 | 在编译时 | 在运行时(通过 type()) |
| 示例 | int, str, list | 用户定义的类 |
CPython 实现对静态类型有特殊处理,以在多个解释器之间维护它们。
来源
Python 使用多种缓存机制来提高属性查找性能。
类型属性查找被缓存到全局缓存中,以加快重复的属性访问。该缓存根据类型的版本标签和属性名称的哈希值进行索引。
来源
类型系统将 Python 特殊方法(如 __add__)映射到称为“槽”的 C 函数指针。这种映射允许高效地实现操作。
当你在 Python 中实现一个特殊方法时,它会被存储在类型对象中的相应槽位,从而允许直接调用而无需字典查找。
来源
描述符是定义属性访问方式的对象。它们通过 __get__、__set__ 和 __delete__ 等方法来实现描述符协议。
Property 对象、方法和类方法都使用描述符实现。
来源
稳定 ABI(应用程序二进制接口)确保 Python C API 的某些部分在 Python 版本之间保持兼容。许多基础对象和类型系统函数都是此稳定 ABI 的一部分。
稳定 ABI 中对象系统的关键部分包括:
| 类别 | 函数/结构 |
|---|---|
| 基本对象 | PyObject, PyObject_* 函数 |
| 类型系统 | PyTypeObject, PyType_* 函数 |
| 引用计数 | Py_INCREF, Py_DECREF |
| 类型检查 | PyObject_IsInstance, PyType_IsSubtype |
来源
PyObject和类型系统构成了Python面向对象能力的基础。通过提供通用的结构和灵活的类型定义机制,CPython在通过插槽函数和缓存等关键优化保持性能的同时,实现了Python的动态特性。类型系统在动态灵活性和性能优化之间的平衡是Python作为一种语言取得成功 Thus Key。