欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python對象的底層實(shí)現(xiàn)源碼學(xué)習(xí)

 更新時間:2022年05月18日 08:48:39   作者:Blanker_711  
這篇文章主要為大家介紹了Python對象的底層實(shí)現(xiàn)源碼學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

在“Python源碼學(xué)習(xí)筆記:Python萬物皆對象”中,我們對Python的對象類型體系有了一定的認(rèn)識,這篇博客將從源碼層面來介紹Python中萬物皆對象的底層實(shí)現(xiàn)。

1. PyObject:對象的基石

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

C源碼如下:

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

源碼解讀:

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

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

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

2. PyVarObject:變長對象的基礎(chǔ)

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

C源碼如下:

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

定長對象和變長對象的大致結(jié)構(gòu)圖示如下:

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

#define PyObject_HEAD       PyObject ob_base;
#define PyObject_VAR_HEAD   PyVarObject ob_base;

2.1 浮點(diǎn)對象

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

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

typedef struct {
    PyObject_HEAD
    double ob_fval;
} PyFloatObject;

圖示如下:

2.2 列表對象

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

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

typedef struct {
    PyObject_VAR_HEAD
    PyObject **ob_item;
    Py_ssize_t allocated;
} PyListObject;

源碼解讀:

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

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

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

圖示如下:

3. PyTypeObject:類型的基石

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

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

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

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 */
    PyObject *tp_bases;
	// ...
} PyTypeObject;

源碼解讀:

PyObject_VAR_HEAD表示PyTypeObject是變長對象

tp_name:類型名稱

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

tp_print、tp_getattr等:表示該類型支持的相關(guān)操作信息

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

PyTypeObject就是類型對象在C層面的表示形式,對應(yīng)面向?qū)ο笾?rdquo;類“的概念,其中保存著對象的”元信息“(即一類對象的操作、數(shù)據(jù)等)。

下面以浮點(diǎn)類型為例,列出了PyFloatObject和PyTypeObject之間的關(guān)系結(jié)構(gòu)圖示:(其中兩個浮點(diǎn)實(shí)例對象都是PyFloatObject結(jié)構(gòu)體,浮點(diǎn)類型對象float是一個PyTypeObject結(jié)構(gòu)體變量)

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

PyTypeObject PyFloat_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "float",
    sizeof(PyFloatObject),
    0,
    (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所對應(yīng)的C語言層面結(jié)構(gòu)體變量:PyType_Type,C源碼如下:(只列出了部分)

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 */
    // ...
    (reprfunc)type_repr,                        /* tp_repr */
    // ...
};

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

把PyType_Type加入到結(jié)構(gòu)圖中,圖示如下:

5. PyBaseObject_Type:類型之基

object是另外一個特殊的類型,它是所有類型的基類。如果要找到object對應(yīng)的結(jié)構(gòu)體,我們可以通過PyFloat_Type的tp_base字段來尋找,因?yàn)樗赶虻木褪莊loat的基類object。但是我們查看源碼發(fā)現(xiàn),PyFloat_Type中并沒有初始化tp_base字段:

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

void
_Py_ReadyTypes(void)
{
    if (PyType_Ready(&PyBaseObject_Type) < 0)
        Py_FatalError("Can't initialize object type");
    if (PyType_Ready(&PyType_Type) < 0)
        Py_FatalError("Can't initialize type type");
    // ...
    if (PyType_Ready(&PyFloat_Type) < 0)
        Py_FatalError("Can't initialize float type");
    // ...
}

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

int
PyType_Ready(PyTypeObject *type)
{
    // ...
    /* Initialize tp_base (defaults to BaseObject unless that's us) */
    base = type->tp_base;
    if (base == NULL && type != &PyBaseObject_Type) {
        base = type->tp_base = &PyBaseObject_Type;
        Py_INCREF(base);
    }
    // ...
}

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

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

PyTypeObject PyBaseObject_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設(shè)置為PyType_Type,即object的類型是type

將PyBaseObject_Type加入到結(jié)構(gòu)圖中,圖示如下:

6. 補(bǔ)充

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

答:

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

在PyBaseObject_Type初始化時,會將ob_tyep字段設(shè)置為PyType_Type,即object的類型為type;在_Py_ReadyTypes函數(shù)中,會通過PyType_Ready()設(shè)置PyType_Type的tp_base字段為PyBaseObject_Type。所以這里本質(zhì)上不是一個先有雞還是先有蛋的問題。

PyTypeObject保存元信息:某種類型的實(shí)例對象所共有的信息保存在類型對象中,實(shí)例對象所特有的信息保存在實(shí)例對象中。以float為例:

  • 無論是3.14,還是2.71,作為float對象,它們都支持加法運(yùn)算,因此加法處理函數(shù)的指針就會保存在類型對象中,即float中。
  • 而這兩個float對象的具體值都是各自特有的,因此具體數(shù)值會通過一個double類型的字段保存在實(shí)例對象中。

以上就是Python對象的底層實(shí)現(xiàn)源碼學(xué)習(xí)的詳細(xì)內(nèi)容,更多關(guān)于Python對象底層的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • opencv python如何實(shí)現(xiàn)圖像二值化

    opencv python如何實(shí)現(xiàn)圖像二值化

    這篇文章主要介紹了opencv python如何實(shí)現(xiàn)圖像二值化,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • Python如何使用turtle庫繪制圖形

    Python如何使用turtle庫繪制圖形

    這篇文章主要介紹了Python如何使用turtle庫繪制圖形,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • Python2隨機(jī)數(shù)列生成器簡單實(shí)例

    Python2隨機(jī)數(shù)列生成器簡單實(shí)例

    這篇文章主要介紹了Python2隨機(jī)數(shù)列生成器,結(jié)合簡單實(shí)例形式分析了Python基于random模塊操作隨機(jī)數(shù)的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-09-09
  • Python API len函數(shù)操作過程解析

    Python API len函數(shù)操作過程解析

    這篇文章主要介紹了Python API len函數(shù)操作過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • Python中schedule模塊定時任務(wù)的使用方法(2)

    Python中schedule模塊定時任務(wù)的使用方法(2)

    這篇文章主要介紹了Python中schedule模塊定時任務(wù)的使用方法,文章基于上一篇文章的內(nèi)容展開的后續(xù),需要的朋友可以參考一下
    2022-05-05
  • Flask-Sqlalchemy的基本使用詳解

    Flask-Sqlalchemy的基本使用詳解

    本文主要介紹了Flask-Sqlalchemy的基本使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 使用Python進(jìn)行數(shù)獨(dú)求解詳解(一)

    使用Python進(jìn)行數(shù)獨(dú)求解詳解(一)

    本文主要介紹了如何構(gòu)建一個Python腳本來解決數(shù)獨(dú)難題,本文的重點(diǎn)在于介紹用于構(gòu)建數(shù)獨(dú)求解器的回溯算法。感興趣的小伙伴可以學(xué)習(xí)一下
    2022-02-02
  • tensorflow-gpu2.3版本安裝步驟

    tensorflow-gpu2.3版本安裝步驟

    這篇文章主要介紹了tensorflow-gpu2.3版本安裝步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 學(xué)習(xí)python 之編寫簡單乘法運(yùn)算題

    學(xué)習(xí)python 之編寫簡單乘法運(yùn)算題

    這篇文章主要介紹了學(xué)習(xí)python 第一季 編寫簡單乘法運(yùn)算題,需要的朋友可以參考下
    2016-02-02
  • Python利用wxPython實(shí)現(xiàn)長文本處理

    Python利用wxPython實(shí)現(xiàn)長文本處理

    這篇文章主要為大家詳細(xì)介紹了Python如何利用wxPython實(shí)現(xiàn)長文本處理功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-05-05

最新評論