python源碼 - 對象

本來想寫python type object之間的區別,聯繫,可是看着寫着,發現東西太多,因而分幾個部分來寫吧,這是第一部分,python中的萬物理論,對象python

 

python內的對象

python中一切皆對象,不管是一個數字或一個字符串或一個類或一個類實例等都是對象,那麼對象究竟是什麼,來看object.h源碼文件中對於對象的描述:git

在Python中,對象就是爲C中的結構體在堆上申請的一塊內存。通常來講,對象是不能被靜態初始化的,而且也不能在棧空間上生存。惟一的例外是類型對象,Python中全部的內建類型對象都是被靜態初始化的。github

在Python中,一個對象一旦被建立,它在內存中的大小就是不變的了。這就意味着那些須要容納可變長度數據的對象只能在對象內維護一個指向一塊可變大小的內存區域的指針。python2.7

一個對象維護着一個「引用計數」,其在一個指向這個對象的指針複製或刪除時增長或減小。當這個引用計數變爲零時,也就是說已經沒有任何指向這個對象的引用,這個對象就能夠從堆上被移除。spa

一個對象有着一個類型(type),來肯定它表明和包含什麼類型的數據。一個對象的類型在它被建立時是固定的。類型自己也是對象。一個對象包含一個指向與之相配的類型的指針。類型本身也有一個類型指針指向着一個表示類型對象的類型的對象「type」,這個type對象也包括一個類型指針,不過是指向它本身的。指針

基本上Python對象的特性就是這些,那麼,在C的層面上,一個Python對象的這些特性是如何實現的呢?code

 

對象機制的基石-PyObject

python中一切皆對象,全部對象都基於PyObject,都有共同的內容定義,這些內容在object.h中大約106行定義。對象

typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

閱讀以上代碼,咱們會發現:內存

  • _PyObject_HEAD_EXTRA這個宏定義了next和prev指針,用來支持用一個雙鏈表把全部堆中的對象串起來。可暫時不用關注
  • *ob_type是一個指向_typeobject結構體的指針,他其實對應着Python中一個很是特殊的對象——指定一個對象類型的類型對象;比較有意思的是,type也是一個對象,type對象的類型是它自己,因此type對象的類型指針就指向它本身了。
  • ob_refcnt是Py_ssize_t結構體的一個實例,與python的內存管理有關,用來實現基於自動引用計數器的垃圾回收機制,在python2.5版本中,這個ob_refcnt是很簡單的,int類型,每當有一個PyObject*引用X對象時,X對象的ob_refcnt加一,當PyObject*被刪除時,X對象的ob_refcnt減一當減到0時,將X對象從堆中釋放,將空間供別的對象使用。在python2.7中,這個稍微作了一些修改,ob_refcnt成了Py_ssize_t的實例,但本質沒有發生變化,依然是經過引用計數器和環路檢測來實現垃圾回收機制。

 

定長對象和變長對象

在Python2中,一個int類型的對象的值在C中的類型是不變的(int),因此它在內存中佔據的大小也是不變的。可是一個字符串對象事先咱們根本不可能知道它所維護的值的大小。在C中,根本就沒有「一個字符串」的概念,字符串對象應該維護「n個char型變量」。不僅是字符串,list等對象也應該維護「n個PyObject對象」。這種「n個……」也是一類Python對象的共同特徵,所以,Python在PyObject以外,還有一個表示這類對象的結構體-PyVarObject,在object.h中大約112行定義。:字符串

typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

咱們把相似Python2中的int對象這樣不包含可變長度的對象稱爲「定長對象」,而字符串對象這樣包含可變長度數據的對象稱爲「變長對象」。

爲何要強調Python2中的int對象呢?由於在Python3中,int類型的底層實現直接使用了Python2中的long類型的底層實現,也就是說,如今的int是之前的long類型,而之前的int類型已經不復存在。而long類型實際是一個變長對象。

變長對象一般都是容器,ob_size這個成員實際上就是指明瞭變長對象中一共容納了多少個元素,即前面講的「n個......」

從PyVarObject的定義能夠看出,變長對象實際就是在PyObject對象後面加了個ob_size,所以,對於任意一個PyVarObject,其所佔用的內存開始部分的字節就是一個PyObject。在Python內部,每個對象都擁有着相同的對象頭部。這就使得在Python中,對對象的引用變得很是的統一,咱們只須要用一個PyObject *指針就能夠引用任意的一個對象。

對象結構圖示

相關文章
相關標籤/搜索