python源碼學習 之 對象建立和對象的行為
來源:互聯網
上載者:User
在將對象的建立和行為之前,我們先來看一下類型對象,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