Python物件基石:PyObject
總是在說Python一切皆物件 ,既然要分析Python原始碼,就必然要看一下它是怎麼實現的(當然不可能一次將它的物件機制都介紹了),在Python直譯器的C層面,一切物件都是以PyObject為基礎的
1. 檢視定義
PyObject
定義位置:Include/object.h
typedef struct _object { _PyObject_HEAD_EXTRA Py_ssize_t ob_refcnt; struct _typeobject *ob_type; } PyObject;
沒錯,在C層面,物件就是一個結構體
-
_PyObject_HEAD_EXTRA
:它會實現一個雙向連結串列,但是隻有在巨集Py_TRACE_REFS被定義時,也就是Py_DEBUG被定義了,Python直譯器Release版本是不會有它的,目標只是分析原始碼的話完全可以忽略他 -
ob_refcnt
:即object reference count,引用計數的,這是和垃圾處理機制有關的,當它減少為0的時候,就是它被刪除的時候了,只至於Py_ssize_t
,把它當做int
或者long
即可 -
ob_type
:它指向的是一個PyTypeObject
,舉個例子,整型物件PyLongObject
的ob_type
指向的就是PyLong_Type
,這個更具體內容的會在介紹PyTypeObject
的時候涉及的
2. 獲取屬性
有了這些屬性,要能獲取到他們,C中獲取它們的方式是通過巨集:
#define Py_REFCNT(ob)(((PyObject*)(ob))->ob_refcnt) #define Py_TYPE(ob)(((PyObject*)(ob))->ob_type)
此時ob就相當於是一個引數,將它強制轉換為一個PyObject,拿到它的引用ob_refcnt
以及ob_type
3. 其它
PyObject內容相當的簡潔,它儲存了每個物件必有的東西,每個Python物件記憶體的最前面的一塊就放著PyObject,所以各種物件可以通過強制轉換為PyObject來單獨訪問ob_refcnt
以及ob_type
屬性
在Python3.6.4中,它是通過在物件最前面放一個PyObject變數實現的
typedef struct { PyObject ob_base;// 物件頭 Py_ssize_t ob_size; } PyVarObject;
在其它的版本中,至少是在2.7.11中,它定義了PyObject_HEAD
巨集,包含了最基本的內容,然後在PyObject以及其它物件前面放入這個巨集
// \可以將一個較長的巨集分行 #define PyObject_HEAD\ _PyObject_HEAD_EXTRA\ Py_ssize_t ob_refcnt;\ struct _typeobject *ob_type; typedef struct _object { PyObject_HEAD// 物件頭 } PyObject; typedef struct { PyObject_HEAD// 物件頭 long ob_ival; } PyIntObject
當然,本質上兩者最終目標都是一樣的