元素名稱 | 說明 |
---|---|
ob_refcnt | 引用計數,對象被其他地方引用時加一,引用解除時減一; 當引用計數為零,便可將對象回收,這是最簡單的垃圾回收機制。 |
ob_type | 類型指針指向對象的類型對象,類型對象描述實例對象的數據及行為。 |
_PyObject_HEAD_EXTRA | 宏,同樣定義在Include/object.h頭文件內。 |
#ifdef Py_TRACE_REFS /* 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
如果Py_TRACE_REFS
被定義,宏展開為兩個指針ob_next
和ob_prev
用來實現雙向鏈表。注釋中說明,雙向鏈表用于跟蹤所有活躍堆對象,一般不啟用,不深入介紹。
用于表示變長對象的PyVarObject
結構體是在PyObject
結構體的基礎上加入長度信息。
typedef struct { PyObject ob_base; Py_ssize_t ob_size; /* Number of items in variable part */ } PyVarObject;
相比object
結構體增加了ob_size
字段用于記錄元素個數。
具體實例對象視其內存大小是否固定,決定其屬于定長對象還是變長對象。相應的需要具有頭部信息PyObject
或PyVarObject
。
因此,頭文件準備了兩個頭部信息的宏定義PyObject_HEAD
和PyObject_VAR_HEAD
,方便對象使用,
#define PyObject_HEAD PyObject ob_base; #define PyObject_VAR_HEAD PyVarObject ob_base;
宏定義說明,
#define PyObject_HEAD PyObject ob_base; 表示將代碼中其他出現PyObject_HEAD的地方,替換成PyObject ob_base;
內存大小固定的浮點數類的實現只需在PyObject
頭部基礎上,用一個雙精度浮點數double加以實現,
typedef struct { PyObject_HEAD double ob_fval; } PyFloatObject;
內存大小不固定的列表對象則需要在PyVarObject
頭部的基礎上,用一個動態數組加以實現,數組存儲列表包含的對象,即 PyObject 指針,
typedef struct { PyObject_VAR_HEAD PyObject **ob_item; Py_ssize_t allocated; } PyListObject;
PyListObject底層由一個數組實現,關鍵字段是以下3個,
字段 | 說明 |
---|---|
ob_item | 指向動態數組的指針,數組保存元素對象指針。 |
allocated | 動態數組總長度,即列表當前的 容量。 |
ob_size | 當前元素個數,即列表當前的 長度。 |
列表容量不足時,Python會自動擴容,具體機制見list源碼解讀。
PyObject_HEAD_INIT
用于定長對象頭部信息初始化。將引用計數ob_refcnt
設置為1并將對象類型ob_type
設置成給定類型。
#define PyObject_HEAD_INIT(type) \ { _PyObject_EXTRA_INIT \ 1, type },
PyVarObject_HEAD_INIT
用于變長對象頭部信息初始化。在前者基礎上進一步設置長度字段ob_size
。
#define PyVarObject_HEAD_INIT(type, size) \ { PyObject_HEAD_INIT(type) size },
在源碼中經常見到這兩個宏定義。
PyObject
記錄了Python中所有對象共有的信息。如引用計數、類型指針和變長對象特有的元素個數。但是還有一些細節需要考慮,
這些作為對象的元信息 ,應該由一個獨立實體保存,與對象所屬類型密切相關。PyObject
中包含的ob_type
指針,指向一個類型對象。類型對象PyTypeObject
也在Include/object.h
中定義,關鍵字段如下,
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; // ... /* Attribute descriptor and subclassing stuff */ struct _typeobject *tp_base; // ...... } PyTypeObject;
類型對象PyTypeObject
是一個變長對象,包含變長對象頭部信息PyObject_VAR_HEAD
和專有字段,
字段 | 說明 |
---|---|
類型名稱 | tp_name字段 |
類型的繼承信息 | tp_base字段指向基類對象 |
創建實例對象時所需的內存信息 | tp_basicsize 和 tp_itemsize 字段 |
該類型支持的相關操作信息 | tp_print、tp_getattr等函數指針 |
PyTypeObject
就是類型對象在 Python 中的表現形式,對應著面向對象中“類”的概念。PyTypeObject
結構很復雜,目前只需要知道它保存著對象的元信息,描述對象的類型即可。
以float為例,考察類型對象和實例對象在內存中的形態和關系,
>>> float class 'float'> >>> pi = 3.14 >>> e = 2.71 >>> type(pi) is float True
PyFloatObject
結構體,除了公共頭部字段ob_refcnt
和ob_type
,專有字段ob_fval
保存了對應的數值。PyTypeObject
結構體,保存了類型名、內存分配信息以及浮點數相關操作。實例對象的ob_type
字段指向類型對象,Python 據此判斷對象類型,進而獲悉關于對象的元信息。上圖的內容并不完全正確,更深入的解讀見后一篇博文。
到此這篇關于Python源碼學習之PyObject和PyTypeObject的文章就介紹到這了,更多相關PyObject和PyTypeObject內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!