《python源码剖析》笔记 python对象初探


 

 

1. 在python中,对象就是为C中的结构体在堆上申请的一块内存。对象不能被静态初始化,也不能在栈空间生存。但内建的类型对象都是被静态初始化的。

2. 对象创建后大小不变。可变对象有一指针指向可变大小的内存区域。

3. 对象机制的基石:PyObject

定长对象:

typedef struct _object{
           PyObject_HEAD
}PyObject;

release模式编译-->

 

typedef struct _object{
           intob_refcnt; // 引用计数,垃圾收集机制
           struct_typeobject *ob_type;// 类型信息,指定对象类型
}PyObject;

PyObject是python对象共有,对象在内存中最开始的字节。

变长对象:

 

#define PyObject_VAR_HEAD 
           PyObject_HEAD
           intoob_size; // 可变长部分可容纳的元素个数
 
typedef struct{
           PyObject_VAR_HEAD
}PyVarObject;

在Python内部,每一个对象都拥有相同的对象头部。我们只需要用一个PyObject *指针就可以引用任意的一个对象。

eg:

 

//PyIntObject对象
typedef struct{
           PyObject_HEAD
           longob_ival; // 保存值
}
//pythonStringObject对象
typedef struct{
           PyObject_VAR_HEAD
           longob_shash;
           into b_sstate;
           charob_sval[1];
} PyStringObject;
//PyListObject对象
typeDef struct{
           PyObject_VAR_HEAD
           PyObjct**ob_item;
           intallocated;
}PyListObject;
//PyDictObject对象
typedef struct{
           Py_ssize_tme_hash;
           PyObject*me_key;
           PyObject*me_value;
}PyDictEntry;
\

4. 类型对象(_typeobject类型--> 面向对象理论中“类”概念的实现 )

 

typedef struct _typeobject{
           PyObject_VAR_HEAD//类型对象也是对象,而且是变长对象
           char*tp_name;  //类型的名称,打印时会用到
           inttp_basicsize, tp_itemsize;  //该类型占用内存的大小,分配内存时会用到
 
           /*与该类型对象相关联的操作信息*/
destructor tp_dealloc;
printfunc tp_print;
//…
} PyTypeObject;

PyType_Type (metaclass), PyInt_Type, PyString_Type,PyDict_Type, PyList_Type是 _typeobject的实例化对象

5. 引用计数

 

Py_INCREF(op) //增加一个对象的引用计数
Py_DECREF(op) //减少一个对象的引用计数

当引用计数减少到0之后,Py_DECREF将调用该对象的析构函数来释放该对象占有的内存和系统资源。这个析构动作是通过对象对应的类型对象中定义的一个函数指针来指定的,即tp_dealloc

调用析构函数并不意味着最终一定用调用free释放空间,Python中大量采用了内存对象池技术来避免频繁地申请和释放内存空间。

类型对象永远不会被析构。

6. 对象的创建

6.1Python C API(内建类型一般采用这种方式)

 

//范型的API
PyObject *intObj = PyObject_New(PyObject, &PyInt_Type);
//类型相关的API
PyObject *intObj= PyInt_FromLong(10)

 

6.2类型对象PyInt_Type (自定义类型只能通过这种方式)

int(10) 就是通过PyInt_Type创建了一个整数对象

所有类都是以object为基类的

tp_new --> 对应C++中的new 操作符,申请内存

tp_init --> 对应C++中的构造函数,完成“初始化”对象的操作

7. 对象的行为

PyTypeObject中定义了大量的函数指针,比如 tp_new, tp_init, tp_dealloc, tp_hash,其中有三组非常重要的操作族

tp_as_number -->PyNumberMethods

tp_as_sequence --> PySequenceMethods

tp_as_mapping --> PyMappingMethods

 

typedef PyObject *(*binaryfunc) (PyObject *, PyObject *);
typedef struct{
	binaryfunc nb_add;
	binaryfunc nb_subtract;
	//…
} PyNumberMethods;

typedef struct {
	lenfunc sq_length;
	binaryfunc sq_concat;
	ssizeargfunc sq_repeat;
	ssizeargfunc sq_item;
	ssizessizeargfunc sq_slice;
	ssizeobjargproc sq_ass_item;
	ssizessizeobjargproc sq_ass_slice;
	objobjproc sq_contains;
	/* Added in release 2.0 */
	binaryfunc sq_inplace_concat;
	ssizeargfunc sq_inplace_repeat;
} PySequenceMethods;

typedef struct {
	lenfunc mp_length;
	binaryfunc mp_subscript;
	objobjargproc mp_ass_subscript;
} PyMappingMethods;

 

 

8. 类型的类型(PyType_Type)

用户自定义class对应的PyTypeObject是通过PyType_Type创建的。所有class的class都是PyType_Type

 

PyTypeObject PyType_Type = {
           PyObject_HEAD_INIT(&PyType_Type)
           0,
           “type”,
           //…
};
\

一般类型对象与PyType_Type对象之间的关系

\

 

9. Python对象的多态性

通过PyObject和PyTypect,Python利用C语言完成了C++所提供的对象的多态的特性。Python内部会用一个PyObject *变量,而不是通过一个PyIntObject *(或者其它具体的类型)来保存来维护这个对象,我们并不知道这个指针所指的对象是什么类型,但可以通过所指对象的ob_type域动态进行判断。

eg.

 

void Print(PyObject *object){
           object->ob_type->tp_print(object);//根据object的具体类型调用对应的tp_print。一个函数在不同情况下表现出了不同的行为,即多态
}
 


 


评论关闭