Python對象的底層實現(xiàn)源碼學習_第1頁
Python對象的底層實現(xiàn)源碼學習_第2頁
Python對象的底層實現(xiàn)源碼學習_第3頁
Python對象的底層實現(xiàn)源碼學習_第4頁
Python對象的底層實現(xiàn)源碼學習_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

第Python對象的底層實現(xiàn)源碼學習目錄1.PyObject:對象的基石2.PyVarObject:變長對象的基礎2.1浮點對象2.2列表對象3.PyTypeObject:類型的基石4.PyType_Type:類型的類型5.PyBaseObject_Type:類型之基6.補充在Python源碼學習筆記:Python萬物皆對象中,我們對Python的對象類型體系有了一定的認識,這篇博客將從源碼層面來介紹Python中萬物皆對象的底層實現(xiàn)。

1.PyObject:對象的基石

在Python解釋器的C層面,一切對象都是以PyObject為基礎的

C源碼如下:

typedefstruct_object{

_PyObject_HEAD_EXTRA

Py_ssize_tob_refcnt;

PyTypeObject*ob_type;

}PyObject;

源碼解讀:

_PyObject_HEAD_EXTRA:主要用于實現(xiàn)雙向鏈表(分析源碼時暫時忽略)

ob_refcnt:引用計數(shù),用于垃圾回收機制,當這個參數(shù)減少為0時即代表對象要被刪除了(Py_ssize_t當作int或long即可,感興趣的話可以去看下它的定義)

ob_type:類型指針,指向?qū)ο蟮念愋蛯ο螅≒yTypeObject,稍后介紹),類型對象描述實例對象的數(shù)據(jù)及行為。如PyLongObject的ob_type指向的就是PyLong_Type

2.PyVarObject:變長對象的基礎

PyVarObject與PyObject相比只多了一個屬性ob_size,它指明了邊長對象中有多少個元素

C源碼如下:

typedefstruct{

PyObjectob_base;

Py_ssize_tob_size;/*Numberofitemsinvariablepart*/

}PyVarObject;

定長對象和變長對象的大致結構圖示如下:

宏定義:對于具體對象,視其大小是否固定,需要包含頭部PyObject或PyVarObject,為此,頭文件準備了兩個宏定義,方便其他對象使用:

#definePyObject_HEADPyObjectob_base;

#definePyObject_VAR_HEADPyVarObjectob_base;

2.1浮點對象

這里簡單的以浮點對象作為定長對象的例子,介紹一下相關概念,后續(xù)會詳細分析float對象的源碼。

對于大小固定的浮點對象,需要在PyObject頭部的基礎上,用一個雙精度浮點數(shù)double加以實現(xiàn):

typedefstruct{

PyObject_HEAD

doubleob_fval;

}PyFloatObject;

圖示如下:

2.2列表對象

這里簡單的以列表對象作為變長對象的例子,介紹一下相關概念,后續(xù)會詳細分析list對象的源碼。

對于大小不固定的列表對象,需要在PyVarObject頭部的基礎上,用一個動態(tài)數(shù)組加以實現(xiàn),數(shù)組存儲了列表包含的對象的指針,即PyObject指針:

typedefstruct{

PyObject_VAR_HEAD

PyObject**ob_item;

Py_ssize_tallocated;

}PyListObject;

源碼解讀:

ob_item:指向動態(tài)數(shù)組的指針,數(shù)組中保存元素對象指針

allocated:動態(tài)數(shù)組的總長度,即列表當前的容量

ob_size:當前元素個數(shù),即列表當前的長度(這里的長度是指:列表包含n個元素,則長度為n)

圖示如下:

3.PyTypeObject:類型的基石

問題:不同類型的對象所需存儲空間不同,創(chuàng)建對象時從哪得知存儲信息呢?以及如何判斷一個給定對象支持哪些操作呢?

注意到,PyObject結構體中包含一個指針ob_type,指向的就是類型對象,其中就包含了上述問題所需要的信息

C源碼如下:(只列出了部分,后續(xù)會結合具體類型進行分析)

typedefstruct_typeobject{

PyObject_VAR_HEAD

constchar*tp_name;/*Forprinting,informat"module.name"*/

Py_ssize_ttp_basicsize,tp_itemsize;/*Forallocation*/

/*Methodstoimplementstandardoperations*/

destructortp_dealloc;

printfunctp_print

getattrfunctp_getattr;

setattrfunctp_setattr;

//...

/*Attributedescriptorandsubclassingstuff*/

PyObject*tp_bases;

//...

}PyTypeObject;

源碼解讀:

PyObject_VAR_HEAD表示PyTypeObject是變長對象

tp_name:類型名稱

tp_basicsize、tp_itemsize:創(chuàng)建實例對象時所需的內(nèi)存信息

tp_print、tp_getattr等:表示該類型支持的相關操作信息

tp_bases:指向基類對象,表示類型的繼承信息

PyTypeObject就是類型對象在C層面的表示形式,對應面向?qū)ο笾蓄惖母拍睿渲斜4嬷鴮ο蟮脑畔ⅲ匆活悓ο蟮牟僮?、?shù)據(jù)等)。

下面以浮點類型為例,列出了PyFloatObject和PyTypeObject之間的關系結構圖示:(其中兩個浮點實例對象都是PyFloatObject結構體,浮點類型對象float是一個PyTypeObject結構體變量)

由于浮點類型對象唯一,在C語言層面作為一個全局變量靜態(tài)定義即可。C源碼如下:(只列出了部分)

PyTypeObjectPyFloat_Type={

PyVarObject_HEAD_INIT(PyType_Type,0)

"float",

sizeof(PyFloatObject),

(destructor)float_dealloc,/*tp_dealloc*/

//...

(reprfunc)float_repr,/*tp_repr*/

//...

源碼解讀:

第二行PyVarObject_HEAD_INIT(PyType_Type,0):初始化了ob_refcnt、ob_type、ob_sie三個字段,其中ob_type指向了PyType_Type(稍后會繼續(xù)介紹,它就是type),即:float的類型是type

第三行float:將tp_name字段初始化為類型名稱float

4.PyType_Type:類型的類型

通過PyFloat_Type的ob_type字段,我們找到了type所對應的C語言層面結構體變量:PyType_Type,C源碼如下:(只列出了部分)

PyTypeObjectPyType_Type={

PyVarObject_HEAD_INIT(PyType_Type,0)

"type",/*tp_name*/

sizeof(PyHeapTypeObject),/*tp_basicsize*/

sizeof(PyMemberDef),/*tp_itemsize*/

(destructor)type_dealloc,/*tp_dealloc*/

//...

(reprfunc)type_repr,/*tp_repr*/

//...

內(nèi)建類型和自定義類對應的PyTypeObject對象都是通過這個PyType_Type創(chuàng)建的。在第二行PyVarObject_HEAD_INIT(PyType_Type,0)中,PyType_Type把自己的ob_type字段設置成了它自己,即type的類型是type

把PyType_Type加入到結構圖中,圖示如下:

5.PyBaseObject_Type:類型之基

object是另外一個特殊的類型,它是所有類型的基類。如果要找到object對應的結構體,我們可以通過PyFloat_Type的tp_base字段來尋找,因為它指向的就是float的基類object。但是我們查看源碼發(fā)現(xiàn),PyFloat_Type中并沒有初始化tp_base字段:

同樣地,我們查看Objects文件夾下的各種不同類型所對應的結構體,發(fā)現(xiàn)tp_base字段均沒有初始化,于是尋找將tp_base字段初始化的函數(shù):

void

_Py_ReadyTypes(void)

if(PyType_Ready(PyBaseObject_Type)0)

Py_FatalError("Can'tinitializeobjecttype");

if(PyType_Ready(PyType_Type)0)

Py_FatalError("Can'tinitializetypetype");

//...

if(PyType_Ready(PyFloat_Type)0)

Py_FatalError("Can'tinitializefloattype");

//...

_Py_ReadyTypes中統(tǒng)一調(diào)用了PyType_Ready()函數(shù),為各種類型設置tp_base字段:

int

PyType_Ready(PyTypeObject*type)

//...

/*Initializetp_base(defaultstoBaseObjectunlessthat'sus)*/

base=type-tp_base;

if(base==NULLtype!=PyBaseObject_Type){

base=type-tp_base=PyBaseObject_Type;

Py_INCREF(base);

//...

可以看到,PyType_Ready在初始化tp_base字段時,對于PyBaseObject_Type,不會設置tp_base字段,即object是沒有基類的,這就是為了保證繼承鏈有一個終點。

PyBaseObject_Type源碼如下:(只列出了部分)

PyTypeObjectPyBaseObject_Type={

PyVarObject_HEAD_INIT(PyType_Type,0)

"object",/*tp_name*/

sizeof(PyObject),/*tp_basicsize*/

0,/*tp_itemsize*/

object_dealloc,/*tp_dealloc*/

//...

object_repr,/*tp_repr*/

//...

0,/*tp_base*/

//...

源碼解讀:

第二行PyVarObject_HEAD_INIT(PyType_Type,0):把ob_type設置為PyType_Type,即object的類型是type

將PyBaseObject_Type加入到結構圖中,圖示如下:

6.補充

object的類型是type,type的基類是object。先有雞還是先有蛋?

答:

前面我們提到,在各種類型對應的C語言結構體變量初始化的時候,tp_base字段都是沒有設置具體值的,直到_Py_ReadyTypes()函數(shù)執(zhí)行時,才通過PyType_Ready()去初始化各類型的tp_base。

在PyBaseObject_Type初始化時,會將ob_tyep字段設置為PyType_Type,即object的類型為type;在_Py_ReadyTypes函數(shù)中,會通過PyType_Ready()設置PyType_Type的tp_base字段為PyBaseOb

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論