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

python源碼剖析之PyObject詳解

 更新時(shí)間:2021年05月18日 14:35:43   作者:莫彩  
Python實(shí)現(xiàn)了完全的面向?qū)ο蟮恼Z言特性,所有的類均繼承自object基類,對(duì)應(yīng)著實(shí)現(xiàn)層面的PyObject.為了實(shí)現(xiàn)多態(tài)的特性,Python的實(shí)現(xiàn)過程維護(hù)了一個(gè)類型對(duì)象系統(tǒng),用來記錄類型信息和維護(hù)類的函數(shù)成員,本文為大家詳細(xì)介紹了PyObject,需要的朋友可以參考下

一、Python中的對(duì)象

Python中一切皆是對(duì)象。
————Guido van Rossum(1989)

這句話只要你學(xué)過python,你就很有可能在你的Python學(xué)習(xí)之旅的前30分鐘就已經(jīng)見過了,但是這句話具體是什么意思呢?

一句話來說,就是面向?qū)ο笾械摹邦悺焙汀皩?duì)象”在Python中都是對(duì)象。類似于int對(duì)象的類型對(duì)象,實(shí)現(xiàn)了“類的概念”,對(duì)類型對(duì)象“實(shí)例化”得到的實(shí)例對(duì)象實(shí)現(xiàn)了“對(duì)象”這個(gè)概念。

通常的說法是,對(duì)象是數(shù)據(jù)以及基于這些數(shù)據(jù)的操作的集合。在計(jì)算機(jī)上,一個(gè)對(duì)象實(shí)際上就是一片被分配的內(nèi)存空間,這些內(nèi)存可能是連續(xù)的,也有可能是離散的,這都不重要,重要的是這片內(nèi)存在更高的層次上可以作為一個(gè)整體來考慮,這個(gè)整體就是一個(gè)對(duì)象。在這片內(nèi)存中,存儲(chǔ)著一系列的數(shù)據(jù)以及可以對(duì)這些數(shù)據(jù)進(jìn)行修改或讀取的一系列操作的代碼。

在 Python 中,對(duì)象就是在堆上申請(qǐng)的結(jié)構(gòu)體,對(duì)象不能是被靜態(tài)初始化的,并且也不能是在??臻g上生存的。唯一的例外就是類型對(duì)象(type object),Python中所有的類型對(duì)象都是被靜態(tài)初始化的。在 Python 中,一個(gè)對(duì)象一旦被創(chuàng)建,它在內(nèi)存中的大小就是不變的了。 這就意味著那些需要容納可變長度數(shù)據(jù)的對(duì)象只能在對(duì)象內(nèi)維護(hù)一個(gè)指向一個(gè)可變大小的內(nèi)存區(qū)域的指針。

1.1 對(duì)象機(jī)制的基石PyObject

PyObjectPyVarObject分別表示定長對(duì)象和變長對(duì)象,使用的C的struct實(shí)現(xiàn)的,在結(jié)構(gòu)中分別只定義了 PyObject_HEADPyObject_VAR_HEAD,后者僅僅是前者加上一個(gè)表示容納元素個(gè)數(shù)的ob_size。

[object.h]
/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD \
	_PyObject_HEAD_EXTRA \
	int ob_refcnt; \
	struct _typeobject *ob_type;

#define PyObject_VAR_HEAD \
	PyObject_HEAD \
	int ob_size; /* Number of items in variable part */

而對(duì)于兩者共有的PyObject_HEAD中,只有兩個(gè)東西,一個(gè)是維護(hù)引用計(jì)數(shù)的ob_refcnt和一個(gè)指向類型對(duì)象PyTypeObject結(jié)構(gòu)體的指針。因此, Python 中實(shí)際上對(duì)象機(jī)制的核心非常的簡單,一個(gè)是引用計(jì)數(shù),一個(gè)就是類型。并且Python中每一個(gè)對(duì)象的開始字節(jié)都是相同的頭部,這使得對(duì)Python對(duì)象的引用十分統(tǒng)一,只需要一個(gè)PyObject*可以引用任意一個(gè)對(duì)象。

在這里插入圖片描述

這兩個(gè)結(jié)構(gòu)體定義的只是Python中對(duì)象共有的部分,其他的具體類型會(huì)有額外的結(jié)構(gòu)體來定義,否則的話所有的對(duì)象豈不是都一樣了?比如int類型的結(jié)構(gòu)體定義PyIntObject中包含了PyObject_HEADob_ival后者是一個(gè)long,存放具體的值。

二、類型對(duì)象

那初始化對(duì)象的時(shí)候,去那里獲得對(duì)象的大小呢?只能是在類型對(duì)象PyTypeObject中了!類型對(duì)象中存放了大量對(duì)象的元信息,大小顯然是一種和對(duì)象的類型有關(guān)的元信息!注意,一個(gè)PyObject對(duì)象就是Python中對(duì)面向?qū)ο罄碚撝蓄愡@個(gè)概念的實(shí)現(xiàn),這里面存放了類型名、內(nèi)存空間、操作函數(shù)指針等信息。

2.1 對(duì)象的創(chuàng)建

Python會(huì)用兩種方法創(chuàng)建對(duì)象,一種是泛型API(AOL:Abstract Object Layer),可以應(yīng)用在任何Python對(duì)象上,API內(nèi)不會(huì)有機(jī)制確定最終調(diào)用哪個(gè)具體函數(shù),比如PyObject_New(PyObject, &PyInt_Type)。另一種是類型相關(guān)API(COL:Concrete Object Layer),只能應(yīng)用于具體類型的對(duì)象上,比如PyInt_FromLong(10)。

自定義對(duì)象在Python內(nèi)部不可能存在COL,所以只能根據(jù)其類型對(duì)象來創(chuàng)建實(shí)例對(duì)象,這就需要PyTypeObject中的tp_new函數(shù)指針,如果是自定義對(duì)象,這個(gè)指針可能是空,那就通過PyTypeObjecttp_base找到類型對(duì)象的基類,再找tp_new指針,這個(gè)過程中會(huì)利用類型對(duì)象中記錄的空間信息申請(qǐng)內(nèi)存。對(duì)于 Python 中的任何一種變長對(duì)象,tp_itemsize 這個(gè)域是必須設(shè)置的,tp_itemsize 指明了由變長對(duì)象保存的元素的單位長度,所謂單位長度即是指一個(gè)對(duì)象在內(nèi)存中的長度。這個(gè) tp_itemsizeob_size 共同決定了應(yīng)該額外申請(qǐng)的內(nèi)存的總大小是多少。

內(nèi)建對(duì)象最終會(huì)使用COL完成創(chuàng)建工作。

new函數(shù)完成后,會(huì)執(zhí)行init函數(shù),前者類似于new操作符,后者類似于構(gòu)造函數(shù)。

在這里插入圖片描述

2.2 對(duì)象的行為

像前面說的,對(duì)象的行為被類型對(duì)象中的函數(shù)指針?biāo)x。這些操作中,有三組非常重要的操作族:tp_as_number、tp_as_sequencetp_as_mapping分別指向PyNumberMethods、PtSequenceMethods、PyMappingMethods函數(shù)族結(jié)構(gòu)體。所謂“鴨子類型”,就行能找到該類型對(duì)應(yīng)的操作,就可以當(dāng)做這個(gè)類型來用。

class MyInt(int):
    def __getitem__(self, key):
        return key+str(self)

a=MyInt(1)
b=MyInt(2)
print(a+b)
print(a['somekey'])

可以發(fā)現(xiàn)通過int繼承得到的數(shù)值對(duì)象,通過重寫魔術(shù)方法,使其支持了字典類型的操作,其實(shí)我們可以認(rèn)為是,制定了MyInt這個(gè)類型對(duì)象tp_as_mapping.mp_subscript操作。

2.3 類型的類型

之前說了,作為類的實(shí)現(xiàn)的類型對(duì)象也是Python對(duì)象,那么類型對(duì)象PyObjectob_type指針指向哪呢?是指向自己嗎?盡管我一開始也是這么想的,但可惜這個(gè)答案不對(duì),類型對(duì)象指向的對(duì)象是PyType_Type。這個(gè)對(duì)象在Python類型機(jī)制中很重要,所有用戶自定義class的PyTypeObject對(duì)象都是通過這個(gè)對(duì)象創(chuàng)建的,因此他是Python中的元類(metaclass)。他是所有class的class。而元類的類型是自己,這里出現(xiàn)了我們一開始認(rèn)為會(huì)出現(xiàn)的自己只想自己的情況!

i=1
class A:
    pass
a=A()
print(i.__class__) # 類型對(duì)象
print(i.__class__.__class__) # 元類
print(a.__class__) # 類型對(duì)象
print(a.__class__.__class__) # 元類
print(a.__class__.__class__.__class__) # 指向自己

在這里插入圖片描述

留在這里的疑問:虛線和虛線指向的對(duì)象是啥玩?

三、Python的多態(tài)性

通過 PyObject 和類型對(duì)象, Python 利用 C 語言完成了 C++所提供的繼承和多態(tài)的特性。一開始已經(jīng)提到,Python中所有對(duì)象的前面幾個(gè)字節(jié)都是PyObject類型也就是PyObject_HEAD結(jié)構(gòu)體。因此在 Python 內(nèi)部各個(gè)函數(shù)之間傳遞的都是一種范型指針PyObject*。這個(gè)指針?biāo)傅膶?duì)象究竟是什么類型的,不知道,只能從指針?biāo)笇?duì)象的ob_type域判斷,而正是通過這個(gè)域,Python 實(shí)現(xiàn)了多態(tài)機(jī)制。

真正執(zhí)行的時(shí)候,通過找到實(shí)例對(duì)象指向的類型對(duì)象的函數(shù)指針來執(zhí)行方法。這里同一個(gè)函數(shù)在不同情況下表現(xiàn)出了不同的行為,這正是多態(tài)的核心所在。

四、引用計(jì)數(shù)

在 Python 中,主要是通過Py_INCREF(op)Py_DECREF(op)兩個(gè)宏來增加和減少一個(gè)對(duì)象的引用計(jì)數(shù)。當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)減少到 0 之后, Py_DECREF將調(diào)用該對(duì)象的析構(gòu)函數(shù)(deallocator function)(但是不一定真的釋放該對(duì)象所占有的內(nèi)存和系統(tǒng)資源),即類型對(duì)象中tp_dealloc指向的函數(shù)。例外的是類型對(duì)象,PyTypeObject是超越引用計(jì)數(shù)規(guī)則的,永遠(yuǎn)不會(huì)被析構(gòu),每一個(gè)對(duì)象中指向類型對(duì)象的指針不被視為對(duì)類型對(duì)象的引用。

這有些觀察者模式(Observer)的影子,在ob_refcnt減為 0 之后,將觸發(fā)對(duì)象銷毀的事件;從 Python 的對(duì)象體系來看,各個(gè)對(duì)象又提供了不同的事件處理函數(shù),而事件的注冊(cè)動(dòng)作正是在各個(gè)對(duì)象對(duì)應(yīng)的類型對(duì)象中靜態(tài)完成的。

PyObject中我們看到ob_refcnt是一個(gè) 32 位的整形變量,這實(shí)際是一個(gè)Python所做的假設(shè),即對(duì)一個(gè)對(duì)象的引用不會(huì)超過一個(gè)整形變量的最大值。

五、Python對(duì)象的分類

在這里插入圖片描述

到此這篇關(guān)于python源碼剖析之PyObject詳解的文章就介紹到這了,更多相關(guān)python源碼PyObject內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • PyCharm安裝PyQt5及其工具(Qt Designer、PyUIC、PyRcc)的步驟詳解

    PyCharm安裝PyQt5及其工具(Qt Designer、PyUIC、PyRcc)的步驟詳解

    這篇文章主要介紹了PyCharm安裝PyQt5及其工具(Qt Designer、PyUIC、PyRcc)的步驟,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Python實(shí)現(xiàn)繪制置信區(qū)間

    Python實(shí)現(xiàn)繪制置信區(qū)間

    置信區(qū)間是從觀測數(shù)據(jù)的統(tǒng)計(jì)量計(jì)算的一種估計(jì)值,它給出了一個(gè)可能包含具有特定置信水平的總體參數(shù)的值范圍,下面我們就來看看如何使用Python繪制置信區(qū)間吧
    2024-02-02
  • python+selenium定時(shí)爬取丁香園的新型冠狀病毒數(shù)據(jù)并制作出類似的地圖(部署到云服務(wù)器)

    python+selenium定時(shí)爬取丁香園的新型冠狀病毒數(shù)據(jù)并制作出類似的地圖(部署到云服務(wù)器)

    這篇文章主要介紹了python+selenium定時(shí)爬取丁香園的新冠病毒每天的數(shù)據(jù)并制作出類似的地圖(部署到云服務(wù)器),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • pandas中apply和transform方法的性能比較及區(qū)別介紹

    pandas中apply和transform方法的性能比較及區(qū)別介紹

    這篇文章主要介紹了pandas中apply和transform方法的性能比較,在文中給大家講解了apply() 與transform()的相同點(diǎn)與不同點(diǎn),需要的朋友可以參考下
    2018-10-10
  • 詳解Python調(diào)試神器之PySnooper

    詳解Python調(diào)試神器之PySnooper

    在程序開發(fā)過程中,代碼的運(yùn)行往往會(huì)和我們預(yù)期的結(jié)果有所差別。于是,我們需要清楚代碼運(yùn)行過程中到底發(fā)生了什么?代碼哪些模塊運(yùn)行了,哪些模塊沒有運(yùn)行?輸出的局部變量是什么樣的?PySnooper,能夠大大減少調(diào)試過程中的工作量
    2021-11-11
  • pip更新問題的解決:'python -m pip install --upgrade pip' 報(bào)錯(cuò)問題(最新推薦)

    pip更新問題的解決:'python -m pip install -

    這篇文章主要介紹了pip更新問題的解決:'python -m pip install --upgrade pip' 報(bào)錯(cuò)問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • Django中使用MySQL5.5的教程

    Django中使用MySQL5.5的教程

    這篇文章主要介紹了Django中使用MySQL5.5的教程,本文圖文實(shí)例詳解的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Python實(shí)現(xiàn)遍歷數(shù)據(jù)庫并獲取key的值

    Python實(shí)現(xiàn)遍歷數(shù)據(jù)庫并獲取key的值

    本文給大家分享的是Python實(shí)現(xiàn)遍歷數(shù)據(jù)庫并獲取key的值的方法,主要是使用for循環(huán)來實(shí)現(xiàn),有需要的小伙伴可以參考下。
    2015-05-05
  • Python監(jiān)測屏幕界面內(nèi)容變化并發(fā)送通知方法詳解

    Python監(jiān)測屏幕界面內(nèi)容變化并發(fā)送通知方法詳解

    這篇文章主要為大家介紹了Python監(jiān)測屏幕界面內(nèi)容變化并發(fā)送通知,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • 使用pytorch讀取數(shù)據(jù)集

    使用pytorch讀取數(shù)據(jù)集

    這篇文章主要介紹了使用pytorch讀取數(shù)據(jù)集,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05

最新評(píng)論