2

Python 源码阅读(一)

 2 years ago
source link: https://blog.singee.me/2020/04/19/d429eaf59fcb48919618e88cea0c1bbf/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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 对于所有对象的操作都是利用的它)

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 中的变长对象。

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 大小相同,不过是有符号的。

有意义的宏

#define PyObject_HEAD           PyObject    ob_base;

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

#define PyVarObject_HEAD_INIT(type, size) \
{ PyObject_HEAD_INIT(type) size },
#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 比较复杂,包括了相应类型对象的整个元信息。

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 的定义如下

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

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

PyTypeObject PyType_Type = {
{ PyObject_HEAD_INIT(&PyType_Type) 0 }, /* ob_base */
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
/* 省略后面的部分 */
};
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 */
/* 省略后面的部分 */
};
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 最终指向了自己


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK