1 前言
最近在读《python源码剖析》一书,收获颇丰。 虽然此书成书已久,书中所讲与如今的实现已有颇多不同, 可是程序框架并未有太多改动,再辅以python官网文档, 仍可以借此一窥python源码。
在依据此书参研过程中,所获颇丰,淋漓尽致之余突生记录心得之想,因此开始写这篇博客。 如果我懒癌没发作,那么应该会有若干后续博客,或许会涉及python大部分内置类型的剖析乃至其他; 若不幸懒癌发作,这一篇博客也足以记录足够的知识点以便以后快速想起对象模型相关。
文中代码的依据均是 Python 3.4.2 的源代码。
2 对象模型概览
- 本节内容出自Include/object.h
2.1 PyObject
Python中的对象有一些共有的性质,这些性质被提取出来放在一个固定的结构中:
typedef struct _object { _PyObject_HEAD_EXTRA Py_ssize_t ob_refcnt; struct _typeobject *ob_type; } PyObject; /* _PyObject_HEAD_EXTRA是一个宏。 * 在未定义Py_TRACE_REFS宏时,该宏为空,因此忽略可以忽略该部分 */
PyObject的成员很简单,一个用来表示引用数量的ob_refcnt (注:python实现了引用计数垃圾回收,这个引用数量就是用于这个的。 那个Py_ssize_t可以认为是一个long,总之是一个整形), 一个用来表示对象类型的ob_type。关于对象类型的内容会在后文详细提到。
这个就是python里所有对象在解释器中的通用表示结构。 不仅如此,python的C API中许多函数也接受PyObject*类型的参数。
2.2 PyVarObject
python中,有定长的对象也有变长的对象(不过在python3.4中,关于变长和定长有一些不符合常识的设定,这个以后再说), 像list就是典型的变长对象,它的大小取决于元素个数,是无法预知的。
变长对象也有一些通用特性,这些特性被提取出来放在了下列数据结构中:
typedef struct { PyObject ob_base; Py_ssize_t ob_size; /* Number of items in variable part */ } PyVarObject;
其中的ob_size是变长对象中元素的个数,而不是该对象占用的实际空间大小。 而通过包含PyObject类型的成员,实际上手动实现了一种简单的继承。 为了更清楚的看到这种继承关系以及它在对象模型中的作用, 在后文会给出一个继承关系的图。
2.3 PyTypeObejct
PyTypeObejct是用来表示对象类型的数据结构,其定义如下:(已省略大部分定义以节约空间)
typedef struct _typeobject { 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; /* ... */ } PyTypeObject;
PyTypeObject结构包含了一个类型需要的各类数据,以上文代码列出的成员为例:
- ob_base,它的ob_base成员(也就是ob_base.ob_base)就是代表某一个类型的对象(没错,每一个类型也是一个特殊的对象)
- tp_basicsize, tp_itemsize:和该类型对象大小有关
- tp_name是该类型的名字
- tp_dealloc是这个类型的析构函数
- tp_as_number:作为数值类型的函数族,比如加减乘除之类
上文的代码中省略了大量的函数指针,那些函数指针都是一些类型需要或可能具有的操作。
每一个类型都有一个独立的PyTypeObject类型的变量。 但是注意,由于PyTypeObject也简介包含了一个PyObject类型的成员, 而该成员需要指向某一个PyTypeObject类型的变量, 但显然,无法指向此PyTypeObject。以int类型为例,若int类型所指向的PyTypeObject变量是自身的话, 那么代表int类型的类型就是int类型本身。 但这样首先与直觉不符,int类型作为 一个类型 和int类型的对象作为 一个对象 拥有相同的类型 本身就是很反直觉的。或许有少数类型可以做到这一点,但int类型却明显不在此列, int这个类型和int对象的性质和操作千差万别,绝不可能是同一类型。 其次,和运行结果也不相符,如果在python中运行type(int),并不会显示int,而是显示type。
因此,为了解决这个问题,python中内建了一个元类型PyType_Type(也就是运行type(int)结果中type的来源), PyType_Type是内置类型的类型,它本身的类型也是它自身。
2.4 总结
此时,python对象模型中最基础的三个数据结构已经介绍完了,可是它们之间的关系、 它们和python中类型、对象的关系还不是很明确。 这里上图一张:
如图,不管是PyTypeObject也好,还是PyVarObject也好,都包含了PyObject类型的成员, 因通过这种方法手动实现了继承。
同时,每一个存在的PyObject类型的实例都对应了一个单独的对象, 因此即使是PyTypeObject这样用来表示类型的东西最后也会对应到一个对象上, 只不过这个对象十分特殊。
最后,再用python中的一个简单的int类型的对象来说明对象模型的结构。 以 a = 10 为例:
其中的PyLong_Type是在python3.0以后int类型的结构。 本图有一些不恰当的地方,10这个对象的内容应该更复杂, 它应该是继承自PyObject的一个专门的类型的实例。 不过为了简便,这里就用这种不规范的方法表示了。