目录
在python中,很多模块都是直接由c实现的,所有东西都是对象,即使是int,float等这样的基本数据类型,都是一个对象,比如
>>> import sys
>>> print(sys.getsizeof(int))
416
>>>
一个int就占用416比特,正是因为python对所有东西都封装成了对象,所以python程序运行需要占用的内存就比c,c++,java等要多得多。
在接下来的说明中,一切都参照python3.7.5源码作讲解。
1.对象机制的基石PyObject
在python中,所有东西都是对象,所有对象拥有相同的部分内容,而这内容就是PyObject,所以对象的核心是PyObject。
我们先看看PyObject的定义:
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
ob_refcnt其实是一个计数器,与内存管理机制有关,对于对象A,当 新PyObject*引用A对象时,A的计数器+1,当删除这个PyObject*时A的计数器-1,当A计数器为0时,A将从堆中被回收。
而ob_type是指明一个对象类型的类型对象,_typeobject结构体是python中内部特殊的对象。
所以在python中,对象机制的核心非常简单:引用计数器+类型信息
PyObject是所有类型对象都必须拥有的,它必须放在对象内存占用最开始的那个字节,除了PyObject,还可以新增额外的信息,构成其他类型的对象,比如float类型的结构设计是:
typedef struct {
PyObject_HEAD //PyObject_HEAD定义每个PyObject的初始段。
double ob_fval;
} PyFloatObject;
我们可以看出,float除了PyObject,还有而外的double变量,ob_fval用来存放数值。同理,list,map,set,str等所有对象也是如此:在PyObject之外还定义属于自身的特殊信息。
2.可变对象类型基石PyVarObject
定长对象:拥有固定大小,如int,float等
变长对象:可变元素个数,如str,list等
我们知道,在c 中没有诸如java,python,c++的字符串对象,准确来说,字符串对象维护的是多个char变量,换句话说,python中字符串对象维护的是n个PyObject对象,类似list,dict等对象拥有共同的特征:“n个PyObject”,于是乎就有了PyObject的扩展PyVarObject,它的结构体设计:
typedef struct {
PyObject ob_base;
Py_ssize_t ob_size; /* 可变部分的对象数 */
} PyVarObject;
ob_size记录的是变长对象中容纳了几个元素,比如list有5个元素,那么ob_size就等于5.
每个对象头部都有统一的PyObject,这使得对对象的引用变得非常统一,我们只需一个PyObject* 指针就可以指向任意一个对象。