欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

python源码学习 之 对象创建和对象的行为

程序员文章站 2022-04-17 09:41:08
...
在将对象的创建和行为之前,我们先来看一下类型对象,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