在将对象的创建和行为之前,我们先来看一下类型对象,python是弱类型语言,但并不代表python没有类型,python中处理对象的类型有一个专门的对象,我们称之为类型对象,如果不知道对象的类型就无法为对象开辟内存空间,因为占用内存的大小是对象的元信息,是对象的基本信息,这与对象所属类型密切相关,因此,他一定回出现在python对象所对应的类型对象中,打开python源码中的include文件夹的object.h文件,查看pytypeobject的源码,在大约第324行: typedef struct _typeobject { pyobject_var_head const char *tp_name; /* for printing, in format “.” */ 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__ 结果如下: 实际上,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