菜单

PyObject与类型系统

相关源文件

本文档解释了 CPython 的核心对象模型,重点介绍了基础的 PyObject 结构及其之上的类型系统。它涵盖了 Python 对象在内存中的表示方式、类型如何定义对象行为以及引用计数系统如何管理内存。有关内存分配和垃圾回收的信息,请参阅 垃圾回收

对象结构基础

Python 的“万物皆对象”设计理念通过一个称为 PyObject 的通用基准结构来实现。所有 Python 对象都包含此基准结构,它提供了包括引用计数和类型信息在内的关键元数据。

PyObject 结构

PyObject 结构是 Python 对象系统的基础,为所有对象提供核心元数据。

在带有 GIL 的标准构建中,PyObject 具有此基本结构。

可变大小的对象(如列表和元组)通过 PyVarObject 结构添加了 ob_size 字段。

来源

无 GIL 线程对象结构

在无 GIL 线程构建中(定义了 Py_GIL_DISABLED),对象结构被扩展以支持线程安全的引用计数。

此结构通过 ob_ref_local 字段(用于拥有对象的线程)和原子 ob_ref_shared 字段(用于来自其他线程的引用)来实现每个线程的引用计数。

来源

引用计数系统

Python 使用引用计数进行内存管理。每个对象都有一个指向它的引用计数,当该计数降至零时,对象将被释放。

引用计数操作

Py_INCREFPy_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 结构很复杂,包含许多定义该类型对象行为的字段。

这些字段可分为几类:

  1. 标识字段:名称和大小信息
  2. 方法指针:用于基本操作,如释放、表示
  3. 方法集:用于数字、序列和映射协议
  4. 类型组织:基类型、基类、MRO、字典
  5. 对象生命周期:初始化、分配、释放
  6. 标志:行为控制标志

来源

类型标志和功能控制

类型系统使用标志(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 函数通过初始化所有未设置的字段、设置继承和计算方法解析顺序来准备类型供使用。

来源

方法解析顺序 (MRO)

方法解析顺序决定了在查找属性时搜索基类的顺序。Python 使用 C3 线性化算法来计算一致的 MRO。

来源

静态类型 vs. 堆类型

Python 有两类类型:静态(内置)类型和堆类型(用户定义类)。

静态类型和堆类型的比较

特征静态类型堆类型
内存位置静态分配在堆上分配
垃圾回收不被 GC 跟踪被 GC 跟踪
可被继承如果设置了 BASETYPE 标志始终
可被修改
创建在编译时在运行时(通过 type()
示例int, str, list用户定义的类

CPython 实现对静态类型有特殊处理,以在多个解释器之间维护它们。

来源

类型缓存和性能

Python 使用多种缓存机制来提高属性查找性能。

类型属性查找被缓存到全局缓存中,以加快重复的属性访问。该缓存根据类型的版本标签和属性名称的哈希值进行索引。

来源

高级类型功能

特殊方法和槽

类型系统将 Python 特殊方法(如 __add__)映射到称为“槽”的 C 函数指针。这种映射允许高效地实现操作。

当你在 Python 中实现一个特殊方法时,它会被存储在类型对象中的相应槽位,从而允许直接调用而无需字典查找。

来源

描述符

描述符是定义属性访问方式的对象。它们通过 __get____set____delete__ 等方法来实现描述符协议。

Property 对象、方法和类方法都使用描述符实现。

来源

稳定 ABI 和兼容性

稳定 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。