【CPython3.6源码分析】PyObject/PyObjectType

参考资料

前言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# object.h.8
/* Object and type object interface */
Objects are structures allocated on the heap.
Objects are never allocated statically or on the stack;

An object has a 'reference count' that is increased or decreased when a
pointer to the object is copied or deleted;
when the reference count reaches zero there are no references to the object left
and it can be removed from the heap.

An object has a 'type' that determines what it represents and what kind
of data it contains. An object's type is fixed when it is created.
Types themselves are represented as objects; an object contains a
pointer to the corresponding type object. The type itself has a type
pointer pointing to the object representing the type 'type', which
contains a pointer to itself!).

once allocated an object keeps the same size and address.
Objects that must hold variable-size data can contain pointers to
variable-size parts of the object.

Objects are always accessed through pointers of the type 'PyObject *'.
The type 'PyObject' is a structure that only contains the reference count
and the type pointer.

A standard interface exists for objects that contain an array of items
whose size is determined when the object is allocated.

开篇一段注释,从注释中能提取到很多要点:

  • 对象堆分配、从不栈分配
  • 垃圾回收之引用计数
  • 对象、类型对象、type
  • 容器对象可变依据:持有指针
  • 基石对象 PyObject 与类型转换

PyObject

1
2
3
4
5
6
7
8
9
10
11
12
// object.h.98
typedef struct _object {
// ifdef Py_TRACE_REFS,定义双向链表存储所有堆上存活对象指针
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt; # 引用计数
struct _typeobject *ob_type; # 类型对象指针
} PyObject;

typedef struct {
PyObject ob_base;
Py_ssize_t ob_size; /* Number of items in variable part,作 int 理解*/
} PyVarObject;

在 Python 中,实际上没有任何东西被声明为 PyObject,但所有对象都可以通过 PyObject 进行引用。类似的还有,指向容器的 PyVarObject

PyObject 结构体中包含:

  • 指向类型对象 _typeobject 的指针 ob_type
  • 用于垃圾回收的引用计数 ob_refcnt

对于容器对象,PyObject_VAR_HEAD 用 ob_size 代表元素个数。

PyTypeObject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// include.h.346
typedef struct _typeobject {
PyObject_VAR_HEAD // #define PyObject_VAR_HEAD PyVarObject ob_base;
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */

/* Methods to implement standard operations */
destructor tp_dealloc;
printfunc tp_print;

/* Method suites for standard classes */
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;

/* More standard operations (here for binary compatibility) */
/* Functions to access object as input/output buffer */
/* Flags to define presence of optional/expanded features */
/* Documentation string */
/* call function for all accessible objects */
/* delete references to contained objects */
/* weak reference enabler */
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
/* Attribute descriptor and subclassing stuff */
struct PyMethodDef *tp_methods;
struct PyMemberDef *tp_members;
} PyTypeObject;

创建对象之前,必须知道申请的内存空间大小,而这些元信息就存储在对象的类型对象中。含有头域PyObject_VAR_HEAD,表明类型对象本身是 可变长对象。结构体内存储大量信息,主要包括:

  • 常规信息:类型名、Doc、tp_itemsize、tp_basicsize等
  • 常规方法指针:tp_new、tp_init、tp_free等
  • 函数簇:PyNumberMethods、PySequenceMethods等
1
2
3
4
5
6
// object.h.301
typedef struct {
lenfunc mp_length;
binaryfunc mp_subscript;
objobjargproc mp_ass_subscript;
} PyMappingMethods;

在函数簇 PyMappingMethods 中,定义了支持映射的对象应该支持的操作。反过来说,一旦定义了 其中的方法,那么该对象就支持该方法。正因为 PyTypeObject 中同时定义了三种函数簇,所以才可以实现鸭子类型。

PyType_Type

前面说过,PyVarObject -> PyObject -> PyTypeObject,但 PyTypeObject 内部又存在 PyVarObject。那么,这个内部的 VarObject 的 type 又是什么?此处先来看下

对象-类型-类型对象

  • a = int(10) == 整型对象
  • a.ob_type == PyLong_Type
  • PyLong_Type.ob_type == PyType_Type
  • PyType_Type.ob_type == PyType_Type
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// object.h.85
#define PyObject_HEAD_INIT(type) { 1, type },
#define PyVarObject_HEAD_INIT(type, size) { PyObject_HEAD_INIT(type) size },

// typeobject.c.3383
PyTypeObject PyType_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
/*
ob_base = {ob_refcnt=1, *ob_type=PyType_Type}
ob_size = 0
*/
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
...
type_doc, /* tp_doc */
...
type_init, /* tp_init */
type_new, /* tp_new */
...
};

如上,可以看见 tp_name == ‘type’,即 Python 中 type 的类型对象就是 PyType_Type。第一句,&PyType_Type 印证了 type(type)==type,形成自旋。

对于内建对象,Python 中有定义好的结构体,如 PyLongObject->PyLong_Type。而对于用户创建的类,就必须动态创建 type 对象。我们知道,创建类可以通过 type() 的方式生成,最终将调用 PyType_Type.type_new()。

PyBaseObject_Type

1
2
3
4
5
6
7
8
9
10
11
// typeobject.c.4535
PyTypeObject PyBaseObject_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"object", /* tp_name */
sizeof(PyObject), /* tp_basicsize */

object_methods, /* tp_methods */
object_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
object_new, /* tp_new */
};

从上可以看出,object的类型对象就是PyBaseObject_Type。第一句,&PyType_Type 印证了 type(object)==type,即 object 的类型对象,的类型对象是 PyType_Type。

object VS type

这里要搞清楚的是:

  • 对象,是通过 PyObject 结构体定义的,必须包含 ob_refcnt、ob_type
  • 类型,PyBaseObject_Type、PyType_Type,本身也是可变对象 PyVarObject
  • 普通对象的类型指针,ob_type,指向的是 类型对象:PyBaseObject_Type、PyType_Type
  • 而 PyBaseObject_Type 本身也是对象,也具有 ob_type,指向的是 PyType_Type
  • 最终 PyType_Type 也是对象,其 ob_type,指向的是 自身
1
2
3
4
5
6
7
8
9
10
11
12
PyTypeObject PyList_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"list",
}
PyTypeObject PyLong_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"int",
}
PyTypeObject PyBaseObject_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"object",
}

层次结构:

  1. 基石,PyObject,一切皆对象
  2. 最顶端的是 type,这也正是 type 被称为 metaclass 的原因。
  3. 内置对象 list/int/object等,其类型对象都是指向 type。
  4. 实例对象 int(1),其类型对象是 PyLong_Type。

假设:

  • 没有 1,好像可以照常用,只是不能创建 类了
  • 没有 2, 也可以照常用,只是每次需要自己创建 int等基础类型
  • 没有 3,不能实例化了,啥也干不了

容易混淆的是:

  • object,既可以说是实例对象 3,又可以说是 类型对象 2,还可以说成 python对象 0
  • type,既可以说成实例对象3的类型对象 2,又可以说成元类 1
  • 如果有人问,type 和 object 的关系,就得先问清楚他说的 type和object 指哪一个层面!