標籤:
雖然自己會吐槽python這語言讓人受不了的慢,不過也不得不說python語言在文法上的精鍊,在寫代碼的時候確實會比java方便一些。。。不過由於python無法像java一樣項目的開始先定義一套強型別限制的介面,所以總感覺在寫python的時候有點不踏實。。。不過pycharm從某種程度上通過注釋也能減輕一點這方面的擔憂。。
好了。。。。。決定了要看一下python的實現。。。這裡就先從python的對象結構來說吧。。。。
在python中,所有的東西都是對象,整數是,方法也是,。。總之什麼都是。。。。
在看python的代碼實現中,可以隨處看到指標類型:PyObject*,那麼我們就先來看看PyObject這到底是怎麼定義的吧:
typedef struct _object { //這個是所有python對象的基礎,這個是不可變對象 PyObject_HEAD} PyObject;
他就是整個python環境中最上層的對象結構,很簡單,就包括一個對象頭部,那麼來看看它的定義:
//通過這個結構,將所有對象構成一個雙鏈表/* Define pointers to support a doubly-linked list of all live heap objects. */#define _PyObject_HEAD_EXTRA struct _object *_ob_next; struct _object *_ob_prev;#define _PyObject_EXTRA_INIT 0, 0,#else#define _PyObject_HEAD_EXTRA#define _PyObject_EXTRA_INIT#endif//所有對象共有的資料,這個放在所有對象記憶體的最開始部分,首先是構成對象鏈表的前後執指標,其次是引用數量,以及它的類型對象/** (1)前後指標,構成迴圈鏈表 (2)引用計數 (3)類型對象**//* PyObject_HEAD defines the initial segment of every PyObject. */#define PyObject_HEAD _PyObject_HEAD_EXTRA Py_ssize_t ob_refcnt; struct _typeobject *ob_type;
可以看出,頭部由3部分來構成,首先是一個前後指標,用於將對象構成一個雙向的鏈表,其次就是比較重要的引用計數了。。。然後還有就是類型對象----》每一個對象都有一個指標指向其所指向的類型對象。。。
既然看到了引用計數,那麼就來說說python的GC吧。。。它跟java在GC最大的不同點就是有一套基於引用計數的記憶體回收。。。
(1)每一個對象都關聯一個引用計數,當這個計數為0的時候,那麼它的記憶體就可以被回收了
(2)對於有循環參考的情況,python也有一套可達性分析的gc來回收記憶體。。當然它這部分就比java簡單的多了
上面看的時最基礎的PyObject結構。。。另外這裡還有另外一種結構:PyVarObject,它用於指代一些變長對象,主要是一些容器。。。。
//一般都是一些容器啥的typedef struct { //可變對象的基礎 PyObject_VAR_HEAD} PyVarObject; //即使是可變對象,首先也是有一個統一的對象頭部,ob_size一般用於記錄容器中資料項目個數,注意這裡不是位元組數#define PyObject_VAR_HEAD PyObject_HEAD Py_ssize_t ob_size; /* Number of items in variable part */#define Py_INVALID_SIZE (Py_ssize_t)-1
它其實也就是擴充了一個0b_size欄位。。。本質上也是與PyObject統一的。。。。所以對於PyVarObject,也可以用PyObject指標來引用。。從而達到了統一。。。。
通過上面的內容,我們知道,所有的對象,都會有一個ob_type指標域,用於指向當前對象的類型對象,那麼接下來來看看類型對象的定義:
//這個用來指定一個對象的類型對象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; //在調用print列印類型的時候,將會調用這裡來進行輸出 getattrfunc tp_getattr; //getter函數 setattrfunc tp_setattr; //setter函數 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; //擷取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; //將當前對象作為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;
可以看到,這裡主要是定義了很多公用的函數。。。。同時這裡可以看到最開始他也定義了一個變長對象的頭部PyObject_VAR_HEAD
那麼也就是說,類型對象本身也是一個對象,也可以用PyObject指標來引用。。。。
嗯。。那麼。。這裡問題就來了。。。。既然類型對象也是一個對象。。。。那麼類型對象他自己的類型對象是啥呢。。。?
嗯。。。在python中定義了一個最頂層的類型對象。。。。。
//最頂層的類型對象,它進行一個類型對象的自引用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 */};
這裡可以看到它的類型對象本身引用了自己。。。。。
以後可以看到,所有的python類型對象都將它自己的類型對象指向了PyType_Type
好了。。基本上比較粗略的瞭解了python的對象結構。。。。。
python源碼分析----對象結構