Python 源码阅读(一)

python/cpython

核心知识点

  1. PyObject 永远使用专用的宏函数在堆上分配(不使用静态分配或是在栈上分配)(Type 除外,是使用了静态分配,不过在 Python 2.2 以后也可以将之在堆上分配)
  2. 每个 PyObject 均存在一个 ob_refcnt 来记录指向这个对象的指针数量,当这一数量为 0 时垃圾回收会将之从堆上清除
  3. PyObject 的类型是由一个名为 ob_type 的指向了类型对象 _typeobject 的指针决定的,PyObject 的类型在创建时确定的的,之后不能更改。而 _typeobject 也是一种 PyObject,这种类型对象的 ob_type 指针指向了 PyType_Type, PyType_Type 的 ob_type 指针指向了自己
  4. PyObject 的大小在创建时固定(同一类型不同变量的大小不一定一样,但是一旦创建好了其大小不会改变)。对于一些可变类型来说,采用的方式是一个指向了可变区域的指针。
  5. 实质上的 PyObject 仅仅包含了所有对象所共有的内容 —— 引用计数和指向了类型的指针。访问具体类型的数据是利用强制类型转换实现的,这就要求所有其余类型的头部必须与 PyObject 相同,Python 采用了 PyObject_HEAD 宏来实现。

PyObject

除了注释和宏定义之外,第一个有意义的定义是 PyObject,这可以简单地认为是 Python 中所有元素的「爸爸」(虽然并没有对象直接使用它,但是 Python 对于所有对象的操作都是利用的它)

1
2
3
4
5
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;

_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
2
3
4
typedef struct {
PyObject ob_base;
Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

根据 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
2
3
4
5
6
#define PyObject_HEAD           PyObject    ob_base;

#define _PyObject_EXTRA_INIT
#define PyObject_HEAD_INIT(type) \
{ _PyObject_EXTRA_INIT \
1, type },
1
2
3
4
#define PyObject_VAR_HEAD       PyVarObject ob_base;

#define PyVarObject_HEAD_INIT(type, size) \
{ PyObject_HEAD_INIT(type) size },
1
2
3
#define Py_REFCNT(ob)           (((PyObject*)(ob))->ob_refcnt)
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size)

这些被广泛用于后面定义和操作 PyObject,因此先在此列出防止后面看不太明白

另外就是有一个 Py_LIMITED_API,其作用是限制 API 使用以保证 ABI 稳定,这个主要是为了 C 扩展使用的,在阅读源码过程中可以忽略直接认为其没有定义。

Python源码阅读–Py_LIMITED_API

Stable Application Binary Interface - Python 3.8.2 documentation

PyTypeObject

PyTypeObject 比较复杂,包括了相应类型对象的整个元信息。

1
2
3
4
5
6
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
/* 省略后面的部分 */
} PyTypeObject;

首先可以通过源码的最前一部分的看出 PyTypeObject 是扩展自 PyVarObject 的,也就是说 PyTypeObject 本身也是一个 PyVarObject、是一个变长的 PyObject。

对于 PyTypeObject 而言,包括了类型名、创建这一类型所需要分配的空间大小、与该类型对象相关的操作信息和一些对象属性。

PyType_Type

(这一块的源码在 /Objects/typeobject.c)

PyType_Type 即是 Python 中的 type 类型,也就是「所有类型的类型」

PyType_Type 的定义如下

1
2
3
4
5
6
7
PyTypeObject PyType_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
/* 省略后面的部分 */
};

将上面提到过的宏一步步展开

1
2
3
4
5
6
7
PyTypeObject PyType_Type = {
{ PyObject_HEAD_INIT(&PyType_Type) 0 }, /* ob_base */
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
/* 省略后面的部分 */
};
1
2
3
4
5
6
7
8
9
10
PyTypeObject PyType_Type = {
{
{ _PyObject_EXTRA_INIT 1, &PyType_Type },/* PyObject ob_base */
0 /* ob_size */
}, /* PyVarObject ob_base */
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
/* 省略后面的部分 */
};
1
2
3
4
5
6
7
8
9
10
11
12
13
PyTypeObject PyType_Type = {
{
{
1, /* ob_refcnt */
&PyType_Type /* ob_type */
}, /* PyObject ob_base */
0 /* ob_size */
}, /* PyVarObject ob_base */
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
/* 省略后面的部分 */
};

可以发现 PyType_Type 的 ob_type 最终指向了自己