Python源码分析:对象的起源与多态的实现

python中一切皆是对象,那么这种机制是如何实现的呢?下面就让我们从python的老巢“源码”来看看这个神秘的机制。

typedef struct _object {

PyObject_HEAD

 } PyObject;

typedef struct {

PyObject_VAR_HEAD

} PyVarObject;

看到上面这两个结构体了吗?它们就是万源之源,所有python对象的祖先,为什么有两个祖先呢?这就要从现实时间的数据对象谈起,我们有些数据,像数字、固定矩阵这类数据其元素个数是固定不变的,而像字符串、集合、字典这类数据其元素个数是会上下浮动的。这样python的发明者在设计python时就为这两类数据创造了两个祖先(像人有男人与女人一样,好像不太确切,但本质就是有两个祖先了!):定长数据类型与变长数据类型。

这两个结构体里面的两个变量,其实都是些宏。从源中我们可以找到这些宏的展开:

#define PyObject_HEAD

_PyObject_HEAD_EXTRA

Py_ssize_t ob_refcnt;

struct _typeobject *ob_type;

#define PyObject_VAR_HEAD

PyObject_HEAD

Py_ssize_t ob_size; /* Number of items in variable part */

看得出来,类型多了的这个ob_size就说明了它的变长特性(元素的个数)。

下面我们来仔细看看PyObject_HEAD这个宏的内容:

_PyObject_HEAD_EXTRA:这个宏展开时要么是双向链表的前后指针要么是空,是在跟踪所有对象时使用:想像一下,一个双向链表把python所有的对象串联起来的场景,好宏大呀!

ob_refcnt:这个属性记录该对象被他人引用的次数(后面发现,这个东西是用来进行内存管理的:引用计数式的垃圾回收机制)

ob_type:这个玩意是个重头戏,它实现了python的多态(何谓多态:对于不同的类型的对象,相同名称的方法其表现行为不同),何以见得呢?下面就让我们重点分析下这个ob_type,首先看看ob_type的原型是什么:

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 */

printfunc tp_print;

。。。

/* Method suites for standard classes */

PyNumberMethods *tp_as_number;

PySequenceMethods *tp_as_sequence;

PyMappingMethods *tp_as_mapping;

。。。

} PyTypeObject;

这个结构体在源代码中整整占了84行,天呢!它是个什么,这么多内容。我们重点看几个字段:

PyObject_VAR_HEAD

:嗯,这不是变长数据类型它老祖先里的头‘骨’吗?怎么这里还有呢?没错,你猜对了,我们指明某个对象类型的对象原型 PyTypeObject也是一个对象。至于为什么是变长类型的对象祖先的头’骨‘,还没搞清楚^0^

tp_print:多态的内部原理开始显露了吧!就是通过这个type对象来为具体不同的对象提供不同的方法实现,尽量方法名字都一样。

PyNumberMethodsPySequenceMethodsPyMappingMethods:其实和上面这个tp_print一样,只不它们是个函数族(由函数集构成),类数字操作(比如支持+-×/)、类序列操作(比如[n:m]切片操作)、字典操作(比如dict[key]操作)。

下面就int类型对象对上面这些原理进行验证:

typedef struct {

PyObject_HEAD

long ob_ival;/*看到了吧,python中的intC语言中的long*/

} PyIntObject;

这就是我们的int类型对象,其头部呢?在python源中可以看出,用一系列宏来实现头部的初始化:

#define PyObject_HEAD_INIT(type)

_PyObject_EXTRA_INIT

1, type,

这里的type,从源码中看出,有一个PyType_Type类型,它就是那个描述类型的类型的对象。有点绕了,但是仔细理解下来,也没什么,无外乎:一个int数据,有一个专门描述int类型数据的类型对象,但是不光有int类型的类型对象还有string类型的类型对象。那么就需要有一个要对象来描述这些类型对象,这就是PyType_Type,也就是它可以测试一个对象是不是类型对象。

发表评论