Python 源码阅读(一)
核心知识点
- PyObject 永远使用专用的宏函数在堆上分配(不使用静态分配或是在栈上分配)(Type 除外,是使用了静态分配,不过在 Python 2.2 以后也可以将之在堆上分配)
- 每个 PyObject 均存在一个 ob_refcnt 来记录指向这个对象的指针数量,当这一数量为 0 时垃圾回收会将之从堆上清除
- PyObject 的类型是由一个名为 ob_type 的指向了类型对象 _typeobject 的指针决定的,PyObject 的类型在创建时确定的的,之后不能更改。而 _typeobject 也是一种 PyObject,这种类型对象的 ob_type 指针指向了 PyType_Type, PyType_Type 的 ob_type 指针指向了自己
- PyObject 的大小在创建时固定(同一类型不同变量的大小不一定一样,但是一旦创建好了其大小不会改变)。对于一些可变类型来说,采用的方式是一个指向了可变区域的指针。
- 实质上的 PyObject 仅仅包含了所有对象所共有的内容 —— 引用计数和指向了类型的指针。访问具体类型的数据是利用强制类型转换实现的,这就要求所有其余类型的头部必须与 PyObject 相同,Python 采用了
PyObject_HEAD
宏来实现。
PyObject
除了注释和宏定义之外,第一个有意义的定义是 PyObject,这可以简单地认为是 Python 中所有元素的「爸爸」(虽然并没有对象直接使用它,但是 Python 对于所有对象的操作都是利用的它)
1 | typedef struct _object { |
_PyObject_HEAD_EXTRA 可以忽略,因为根据定义仅仅在 Py_TRACE_REFS 定义了时才有意义(用作定义 _ob_next 和 _ob_prev 两个指向了其他堆上元素的指针),而 Py_TRACE_REFS 定义则要求 Py_DEBUG 被定义,显然生产环境这个宏不会被定义,因此可以将之忽略掉。
也就是说 PyObject 只包含了 ob_refcnt 代表了引用计数、ob_type 代表了对象类型。
另外,PyObject 与struct _object
是相同的(类型别名),与之类似的是这里出现的 struct _typeobject
与后面将会出现的 PyTypeObject 也是相同的。
PyVarObject
源码中紧跟着 PyObject 定义的是 PyVarObject,这一类型代表着 Python 中的变长对象。
1 | typedef struct { |
根据 C 中组织元素的方式,可以认为在 PyVarObject 结构体前端定义 PyObject 的含义是「PyVarObject 是在 PyObject 基础上进行的扩展」,后续在指针操作上将 *PyVarObject 转换为 *PyObject 传递是安全的。Python 中很广泛的利用了 C 的这一指针操作特性。
PyVarObject 相比于 PyObject 只多了一个 ob_size,根据注释可以知道这代表的是 PyVarObject 中可变长度的大小。
Py_ssize_t
PEP 353 – Using ssize_t as the index type
PyObject 和 PyVarObject 中都出现了一个类型叫做 Py_ssize_t
,看名字可以指导这是 Python 自己定义的。
这一类型是 Python 2.4 引入的,现在被广泛用于 Python 各种定义对象大小和元素索引,简单来理解就是替代了常用的 int。这个名字的含义是「Python Signed size_t」,根据 PEP-0353 中的官方说法,这一类型与编译器的 size_t 大小相同,不过是有符号的。
有意义的宏
1 |
1 |
1 |
这些被广泛用于后面定义和操作 PyObject,因此先在此列出防止后面看不太明白
另外就是有一个 Py_LIMITED_API
,其作用是限制 API 使用以保证 ABI 稳定,这个主要是为了 C 扩展使用的,在阅读源码过程中可以忽略直接认为其没有定义。
Stable Application Binary Interface - Python 3.8.2 documentation
PyTypeObject
PyTypeObject 比较复杂,包括了相应类型对象的整个元信息。
1 | typedef struct _typeobject { |
首先可以通过源码的最前一部分的看出 PyTypeObject 是扩展自 PyVarObject 的,也就是说 PyTypeObject 本身也是一个 PyVarObject、是一个变长的 PyObject。
对于 PyTypeObject 而言,包括了类型名、创建这一类型所需要分配的空间大小、与该类型对象相关的操作信息和一些对象属性。
PyType_Type
(这一块的源码在 /Objects/typeobject.c)
PyType_Type 即是 Python 中的 type
类型,也就是「所有类型的类型」
PyType_Type 的定义如下
1 | PyTypeObject PyType_Type = { |
将上面提到过的宏一步步展开
1 | PyTypeObject PyType_Type = { |
1 | PyTypeObject PyType_Type = { |
1 | PyTypeObject PyType_Type = { |
可以发现 PyType_Type 的 ob_type 最终指向了自己