PyObject
在Python中,所有的东西都是对象,而所有的对象都拥有一些相同的内容,这些内容在PyObject中定义,PyObject 是整个Python 对象机制的核心。
// object.h
// object.h
#define _PyObject_HEAD_EXTRA \
struct _object *_ob_next; \
struct _object *_ob_prev;
......
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
PyTypeObject *ob_type;
} PyObject;
- ob_refent与Python的内存管理机制有关,它实现了基于引用计数的垃圾收集机制。对于某一个对象A,当有一个新的pyobject 引用该对象时,A的引用计数应该增加:而当这个Pyobject被删除时,A的引用计数应该减少。当A的引用计数减少到0时,A就可以从堆上被删除,以释放出内存供别的对象使用。
- ob_type是一个指向_typeobject结构体的指针,这个结构体对应着Python 内部的一种特殊对象,它是用来指定一个对象类型的类型对象。
PyObject结构体是Python对象机制的核心基石,从代码中可以看到,在Python中,对象机制的核心其实非常简单,一个是引用计数,一个就是类型信息。
pyobject中定义了每一个Python对象都必须有的内容,这些内容将出现在每一个Python对象所占有的内存的最开始的字节中。这句话的另一个意思是,每一个Python对象除了必须有这个Pyobject内容外,似乎还应该占有一些额外的内存,放置些其他的东西。
变长对象
#define PyObject_VAR_HEAD PyVarObject ob_base;
......
typedef struct {
PyObject ob_base;
Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;
包含可变长度数据的对象称为“变长对象”,它们的区别在于定长对象的不同对象占用的内存大小是一样的,而变长对象的不同对象占用的内存可能是不一样的。比如,整数对象“1"和“100”占用的内存大小都是sizeof (PyIntobject),而字符串对象“Python”和“Ruby"占用的内存大小就不同了。正是这种区别导致了PyVarobject对象中ob_size的出现。变长对象通常都是容器,ob_size 这个成员实际上就是指明了变长对象中一共容纳了多少个元素。注意,ob_size指明的是所容纳元素的个数,而不是字节的数量。
从PyObject_VAR_HEAD的定义可以看出,PyVarobject 实际上只是对Pyobject的一个扩展。因此,对于任何一个PyVarObject,其所占用的内存开始部分的字节的意义和PyObject是一样的。换句话说,在Python内部,每一个对象都拥有相同的对象头部。这就使得在Python中,对对象的引用变得非常的统一。
类型对象
在PyTypeObject结构体中定义了PyTypeObject *ob_type;
。该ob_type指向_typeobject,_typeobject定义在cpython/object.h文件中。事实上,一个PyType0bject对象就是Python中对面向对象理论中“类”这个概念的实现。在_typeobject中定义了许多信息,主要有这几类:
- 类型名,tp.name,主要是Python内部以及调试的时候使用;
- 创建该类型对象时分配内存空间大小的信息,即tp_basicsize 和tp.itemsize;
- 与该类型对象相关联的操作信息(就是诸如tp_print 这样的许多的函数指针);
struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;
Py_ssize_t tp_vectorcall_offset;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
or tp_reserved (Python 3) */
reprfunc tp_repr;
/* Method suites for standard classes */
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
/* More standard operations (here for binary compatibility) */
hashfunc tp_hash;
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
/* Functions to access object as input/output buffer */
PyBufferProcs *tp_as_buffer;
/* Flags to define presence of optional/expanded features */
unsigned long tp_flags;
const char *tp_doc; /* Documentation string */
/* Assigned meaning in release 2.0 */
/* call function for all accessible objects */
traverseproc tp_traverse;
/* delete references to contained objects */
inquiry tp_clear;
/* Assigned meaning in release 2.1 */
/* rich comparisons */
richcmpfunc tp_richcompare;
/* weak reference enabler */
Py_ssize_t tp_weaklistoffset;
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
/* Attribute descriptor and subclassing stuff */
struct PyMethodDef *tp_methods;
struct PyMemberDef *tp_members;
struct PyGetSetDef *tp_getset;
struct _typeobject *tp_base;
PyObject *tp_dict;
descrgetfunc tp_descr_get;
descrsetfunc tp_descr_set;
Py_ssize_t tp_dictoffset;
initproc tp_init;
allocfunc tp_alloc;
newfunc tp_new;
freefunc tp_free; /* Low-level free-memory routine */
inquiry tp_is_gc; /* For PyObject_IS_GC */
PyObject *tp_bases;
PyObject *tp_mro; /* method resolution order */
PyObject *tp_cache;
PyObject *tp_subclasses;
PyObject *tp_weaklist;
destructor tp_del;
/* Type attribute cache version tag. Added in version 2.6 */
unsigned int tp_version_tag;
destructor tp_finalize;
vectorcallfunc tp_vectorcall;
};
对象的创建
Python有两种方法。第一种是通过Python C API来创建,第二种是通过类型对象PyInt_Type。
- Python对外提供了C API,让用户可以从C环境中与Python交互,实际上,因为Python本身也是C写成的,所以Python内部也大量使用了这些API。Python的CAPI分成两类,一类称为范型的API, 或者称为AOL (Abstract Object Layer)。 这类API都具有诸如pyobject_*的形式,可以应用在任何Python对象身上,比如输出对象的PyObject_Print,你可以PyObject_Print(int object) ,也可以Py0bject_Print (string
object),API内部会有一整套机制确定最终调用的函数是哪一一个。 另一类是与类型相关的API,或者称为COL (Concrete Object Layer)。这类API通常只能作用在某一种类型的对象上,对于每一种内建对象,Python都提供了这样的一组API。例如long对象:
PyAPI_FUNC(PyObject *) PyLong_FromLong(long); PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long); PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t); PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t); PyAPI_FUNC(PyObject *) PyLong_FromDouble(double);
对象的行为
在PyTypeObject中定义了大量的函数指针,这些函数指针最终都会指向某个函数,或者指向NULL。这些函数指针可以视为类型对象中所定义的操作,而这些操作直接决定着一个对象在运行时所表现出的行为。在这些操作信息中,有三组非常重要的操作族,在PyTypeObject 中,它们是tp_as_number,tp_as_sequence,tp_as_mapping。它们分别指向PyNumberMethods,pySequenceMethods和PyMappingMethods函数族。对于一种类型来说,它完全可以同时定义三个函数族中的所有操作。换句话说,一个对象可以既表现出数值对象的特性,也可以表现出关联对象的特性。
/* Method suites for standard classes */
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
Comments | NOTHING