您的位置:首页 > 编程语言 > Python开发

python源码 - 对象

2017-10-01 00:00 225 查看
摘要: python里一些皆对象,从对象的数据结构说起

原本想写python type object之间的区别,联系,但是看着写着,发现东西太多,于是分几个部分来写吧,这是第一部分,python中的万物理论,对象

python内的对象

python中一切皆对象,不论是一个数字或一个字符串或一个类或一个类实例等都是对象,那么对象到底是什么,来看object.h源码文件中对于对象的描述:

在Python中,对象就是为C中的结构体在堆上申请的一块内存。一般来说,对象是不能被静态初始化的,并且也不能在栈空间上生存。唯一的例外是类型对象,Python中所有的内建类型对象都是被静态初始化的。

在Python中,一个对象一旦被创建,它在内存中的大小就是不变的了。这就意味着那些需要容纳可变长度数据的对象只能在对象内维护一个指向一块可变大小的内存区域的指针。

一个对象维护着一个“引用计数”,其在一个指向这个对象的指针复制或删除时增加或减少。当这个引用计数变为零时,也就是说已经没有任何指向这个对象的引用,这个对象就可以从堆上被移除。

一个对象有着一个类型(type),来确定它代表和包含什么类型的数据。一个对象的类型在它被创建时是固定的。类型本身也是对象。一个对象包含一个指向与之相配的类型的指针。类型自己也有一个类型指针指向着一个表示类型对象的类型的对象“type”,这个type对象也包括一个类型指针,不过是指向它自己的。

基本上Python对象的特性就是这些,那么,在C的层面上,一个Python对象的这些特性是如何实现的呢?

对象机制的基石-PyObject

python中一切皆对象,所有对象都基于PyObject,都有共同的内容定义,这些内容在object.h中大约106行定义。

typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;

阅读以上代码,我们会发现:

_PyObject_HEAD_EXTRA这个宏定义了next和prev指针,用来支持用一个双链表把所有堆中的对象串起来。可暂时不用关注

*ob_type是一个指向_typeobject结构体的指针,他其实对应着Python中一个非常特殊的对象——指定一个对象类型的类型对象;比较有意思的是,type也是一个对象,type对象的类型是它本身,所以type对象的类型指针就指向它自己了。

ob_refcnt是Py_ssize_t结构体的一个实例,与python的内存管理有关,用来实现基于自动引用计数器的垃圾回收机制,在python2.5版本中,这个ob_refcnt是很简单的,int类型,每当有一个PyObject*引用X对象时,X对象的ob_refcnt加一,当PyObject*被删除时,X对象的ob_refcnt减一当减到0时,将X对象从堆中释放,将空间供别的对象使用。在python2.7中,这个稍微做了一些修改,ob_refcnt成了Py_ssize_t的实例,但本质没有发生变化,依然是通过引用计数器和环路检测来实现垃圾回收机制。

定长对象和变长对象

在Python2中,一个int类型的对象的值在C中的类型是不变的(int),所以它在内存中占据的大小也是不变的。但是一个字符串对象事先我们根本不可能知道它所维护的值的大小。在C中,根本就没有“一个字符串”的概念,字符串对象应该维护“n个char型变量”。不只是字符串,list等对象也应该维护“n个PyObject对象”。这种“n个……”也是一类Python对象的共同特征,因此,Python在PyObject之外,还有一个表示这类对象的结构体-PyVarObject,在object.h中大约112行定义。:

typedef struct {
PyObject ob_base;
Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

我们把类似Python2中的int对象这样不包含可变长度的对象称为“定长对象”,而字符串对象这样包含可变长度数据的对象称为“变长对象”。

为什么要强调Python2中的int对象呢?因为在Python3中,int类型的底层实现直接使用了Python2中的long类型的底层实现,也就是说,现在的int是以前的long类型,而以前的int类型已经不复存在。而long类型实际是一个变长对象。

变长对象通常都是容器,ob_size这个成员实际上就是指明了变长对象中一共容纳了多少个元素,即前面讲的“n个......”

从PyVarObject的定义可以看出,变长对象实际就是在PyObject对象后面加了个ob_size,因此,对于任意一个PyVarObject,其所占用的内存开始部分的字节就是一个PyObject。在Python内部,每一个对象都拥有着相同的对象头部。这就使得在Python中,对对象的引用变得非常的统一,我们只需要用一个PyObject *指针就可以引用任意的一个对象。

对象结构图示

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  object