python源码学习之对象创建和对象的行为
时间:2021-07-01 10:21:17
帮助过:108人阅读
在将对象的创建和行为之前,我们先来看一下类型对象,python是弱类型语言,但并不代表python没有类型,python中处理对象的类型有一个专门的对象,我们称之为类型对象,如果不知道对象的类型就无法为对象开辟内存空间,因为占用内存的大小是对象的元信息,是对象的基本信息,这与对象所属类型密切相关,因此,他一定回出现在python对象所对应的类型对象中,打开python源码中的include文件夹的object.h文件,查看PyTypeObject的源码,在大约第324行:
typedef 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;
printfunc tp_print;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
cmpfunc tp_compare;
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 */
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;
/* Added in release 2.2 */
/* 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;
#ifdef COUNT_ALLOCS
/* these must be last and never explicitly initialized */
Py_ssize_t tp_allocs;
Py_ssize_t tp_frees;
Py_ssize_t tp_maxalloc;
struct _typeobject *tp_prev;
struct _typeobject *tp_next;
#endif
} PyTypeObject;
上面这段代码很长,一个结构体100多行,不过所包含的信息主要分为如下四大类:
1、类型名,tp_name,主要是python内部以及调试时使用,用来识别对象的所属类型;
2、tp_basicsize和tp_itemsize,创建该类对象分配内存空间的大小的信息;
3、与该类对象关联的操作信息,比如说tp_base等指向函数的指针;
4、类型对象的类型信息。
重点1、对象的创建:
python创建对象主要有两种方法,Python C API和PyInt_Type。
Python C API让用户从C环境与Python交互,一共有两种API,一种是AOL(Abstract Object Layer)即泛型API,另一种是COL(Concrete Object Layer)即类型API;AOL都有PyObject_***的形式,可以应用到任何Python对象上,表达式一般表示为:PyObject* intObj = PyObject_new(PyObject,&PyInt_Type),而COL的API一般如下:PyObject* intObj = PyInt_FromLong(1000);我们就创建了一个1000整数对象。
无论采用哪种Python C API,Python都是最终直接分配内存,因为这都是Python的内建对象,而如果我们自己定义了一个类如:class MySelf(object),对于类型MySelf,Python不会使用API来创建,但是Python会通过MySelf所对应的类型对象来创建实例对象,MySelf的类型对象是object,所有Python会通过object来创建MySelf的实例化对象。我们执行如下代码:
class A(object):
pass
a = A()
type(a)
A.__base__
结果如下:
<class ‘__main__.A’>
<type ‘object’>
实际上,Python是先实例化object运行object的构造方法,然后再实例化A,这与Python的底层实现有着密切的联系。任何一个用户自定义的Python类,最终都有一个共同的父类object,实例化时先实例化object类,一次向下,直到实例化用户自定义的类。
Screen Shot 2014-06-14 at 下午12.01.15
对象的行为:
在对象的操作信息中有三组非常重要的操作族,tp_as_number,tp_as_sequence,tp_as_mapping,他们分别指向PyNumberMethods,PySequenceMethods,PyMappingMethods函数族。对于一种对象,他可以同时定义三个函数族中的所有操作,即对象可以表现出数值对象的特性和关联对象的特性,代码如下:
class MyInt(int):
def __getitem__(self,key):
return key+str(self)
a = MyInt(1)
b = MyInt(2)
print a+b
print a['key']
运行结果为:
1
2
3
key1
最后说一下类型对象的类型。对象的类型也是一个对象,那么这个对象的类型又是什么呢?首先可以确定他也是一个对象。我们称之为类型的类型。这个十分、非常、很、very much重要,就是源码中的PyType_Type结构体,这个在objects文件夹的typeobject.c文件里,源代码如下:
PyTypeObject PyType_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
(destructor)type_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)type_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)_Py_HashPointer, /* tp_hash */
(ternaryfunc)type_call, /* tp_call */
0, /* tp_str */
(getattrofunc)type_getattro, /* tp_getattro */
(setattrofunc)type_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TYPE_SUBCLASS, /* tp_flags */
type_doc, /* tp_doc */
(traverseproc)type_traverse, /* tp_traverse */
(inquiry)type_clear, /* tp_clear */
type_richcompare, /* tp_richcompare */
offsetof(PyTypeObject, tp_weaklist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
type_methods, /* tp_methods */
type_members, /* tp_members */
type_getsets, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(PyTypeObject, tp_dict), /* tp_dictoffset */
type_init, /* tp_init */
0, /* tp_alloc */
type_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
(inquiry)type_is_gc, /* tp_is_gc */
};
呵呵,这个看起来很复杂,PyInt_Type和PyType_Type之间如何联系起来的?就是前面博客中所说的引用计数器,一个整数对象运行时如下图所示:
Screen Shot 2014-06-14 at 下午1.32.09