Python源碼學(xué)習(xí)之PyType_Type和PyBaseObject_Type詳解
PyType_Type和PyBaseObject_Type
PyObject和PyTypeObject內(nèi)容的最后指出下圖中對(duì)實(shí)例對(duì)象和類(lèi)型對(duì)象的理解是不完全正確的,

浮點(diǎn)類(lèi)型對(duì)象全局唯一,Python在C語(yǔ)言層面實(shí)現(xiàn)過(guò)程中將其定義為一個(gè)全局靜態(tài)變量,定義于Object/floatobject.c中,命名為PyFloat_Type。
PyTypeObject PyFloat_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"float",
sizeof(PyFloatObject),
0,
(destructor)float_dealloc, /* tp_dealloc */
// ...
(reprfunc)float_repr, /* tp_repr */
// ...
};
- 第2行使用初始化
ob_refcnt、ob_type以及ob_size三個(gè)字段,PyVarObject_HEAD_INIT的定義可以參考博文1.4.3節(jié)的內(nèi)容。 - 第3行將
tp_name字段初始化成類(lèi)型名稱(chēng)"float" - 再往下是各種操作的函數(shù)指針
ob_type指針指向PyType_Type,這也是一個(gè)靜態(tài)定義的全局變量。代表“類(lèi)型的類(lèi)型” 的type對(duì)象就是PyType_Type。
一. 類(lèi)型的類(lèi)型—PyType_Tpye(type的實(shí)體)
上文中,float類(lèi)型對(duì)象在底層實(shí)現(xiàn)過(guò)程中對(duì)應(yīng)PyFloat_Type全局靜態(tài)變量。Python類(lèi)型是一種對(duì)象,也有自己的類(lèi)型,即Python中的type。
>>> float.__class__ <class 'type'>
自定義類(lèi)型也遵循同樣的規(guī)則,
>>> class Foo(object): ... pass ... >>> Foo.__class__ <class 'type'>
在查看PyFloat_Type代碼實(shí)現(xiàn)時(shí),ob_type字段指向的PyType_Type就是type的實(shí)現(xiàn)。在Object/typeobject.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)建類(lèi)型和自定義類(lèi)的
PyTypeObject對(duì)象都是通過(guò)PyType_Type創(chuàng)建。PyType_Type是PyTypeObject的一個(gè)實(shí)例。 PyType_Type是類(lèi)型機(jī)制中至關(guān)重要的對(duì)象,是所有類(lèi)型的類(lèi)型,稱(chēng)為元類(lèi)型。- 第2行代碼處
PyType_Type將自身的ob_type字段指向它自己。
>>> type.__class__ <class 'type'> >>> type.__class__ is type True
由此,以float為例,可以繪制一個(gè)更完善但是并不完全正確的實(shí)例對(duì)象和類(lèi)型對(duì)象在內(nèi)存中的關(guān)系圖,

二. 類(lèi)型之基—PyBaseObject_Type(object的實(shí)體)
上一節(jié)中紅色標(biāo)記的語(yǔ)句,并不完全正確是因?yàn)樗伎歼^(guò)程中忽略了object對(duì)象的存在。
object是另一個(gè)特殊的類(lèi)型,是所有類(lèi)型的基類(lèi)。同樣可以通過(guò)PyFloat_Type中tp_base字段順藤摸瓜找到。然而,在源碼的第2行的PyVarObject_HEAD_INIT定義中,該字段并沒(méi)有初始化,
0, /* tp_base */
更進(jìn)一步查找代碼中PyFloat_Type出現(xiàn)的地方,在Object/object.c中發(fā)現(xiàn)如下代碼,
if (PyType_Ready(&PyFloat_Type) < 0)
Py_FatalError("Can't initialize float type");
創(chuàng)建類(lèi)型對(duì)象過(guò)程中,需要PyType_Ready方法將tp_base字段初始化,具體如下
int
PyType_Ready(PyTypeObject *type)
{
// ...
base = type->tp_base;
if (base == NULL && type != &PyBaseObject_Type) {
base = type->tp_base = &PyBaseObject_Type;
Py_INCREF(base);
}
// ...
}
PyFloat_Type中的tp_base字段初始化成PyBaseObject_Type,它就是object背后的實(shí)體,其源碼定義為,
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 */
};
源碼中ob_type字段指向PyType_Type這與下方object在 Python中的測(cè)試代碼相吻合,
>>> object.__class__ <class 'type'>
此外,PyType_Ready函數(shù)初始化PyBaseObject_Type時(shí),不設(shè)置tp_base字段。 因?yàn)槔^承鏈必須有一個(gè)終點(diǎn),否則沿著繼承鏈查找時(shí)會(huì)陷入死循環(huán)。
>>> print(object.__base__) None
由此,得到了實(shí)例對(duì)象和類(lèi)型對(duì)象在內(nèi)存中完整的關(guān)系圖。以float為例,

到此這篇關(guān)于Python源碼學(xué)習(xí)之PyType_Type和PyBaseObject_Type詳解的文章就介紹到這了,更多相關(guān)PyType_Type和PyBaseObject_Type內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python3 pillow模塊實(shí)現(xiàn)簡(jiǎn)單驗(yàn)證碼
這篇文章主要為大家詳細(xì)介紹了python3 pillow模塊實(shí)現(xiàn)簡(jiǎn)單驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10
弄懂這56個(gè)Python使用技巧(輕松掌握Python高效開(kāi)發(fā))
這篇文章主要介紹了弄懂這56個(gè)Python使用技巧(輕松掌握Python高效開(kāi)發(fā)),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
Django 解決distinct無(wú)法去除重復(fù)數(shù)據(jù)的問(wèn)題
這篇文章主要介紹了Django 解決distinct無(wú)法去除重復(fù)數(shù)據(jù)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-05-05
python 實(shí)用工具狀態(tài)機(jī)transitions
這篇文章主要介紹了python 實(shí)用工具狀態(tài)機(jī)transitions的使用,幫助大家更好的理解和學(xué)習(xí)python,感興趣的朋友可以了解下2020-11-11
python 命名規(guī)范知識(shí)點(diǎn)匯總
這里給大家分享的是在python開(kāi)發(fā)過(guò)程中需要注意的命名的規(guī)范的知識(shí)匯總,有需要的小伙伴可以查看下2020-02-02
python用裝飾器自動(dòng)注冊(cè)Tornado路由詳解
這篇文章主要給大家介紹了python用裝飾器自動(dòng)注冊(cè)Tornado路由,文中給出了三個(gè)版本的解決方法,有需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-02-02
Pytorch結(jié)合PyG實(shí)現(xiàn)MLP過(guò)程詳解
這篇文章主要為大家介紹了Pytorch結(jié)合PyG實(shí)現(xiàn)MLP過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
python+matplotlib繪制旋轉(zhuǎn)橢圓實(shí)例代碼
這篇文章主要介紹了python+matplotlib繪制旋轉(zhuǎn)橢圓實(shí)例代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
解決python cv2.imread 讀取中文路徑的圖片返回為None的問(wèn)題
這篇文章主要介紹了解決python cv2.imread 讀取中文路徑的圖片返回為None的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06

