python源码 - 对象

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

 

python内的对象

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

在Python中,对象就是为C中的结构体在堆上申请的一块内存。通常来讲,对象是不能被静态初始化的,而且也不能在栈空间上生存。惟一的例外是类型对象,Python中全部的内建类型对象都是被静态初始化的。github

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

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

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

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

 

对象机制的基石-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 *指针就能够引用任意的一个对象。

对象结构图示

相关文章
相关标签/搜索