您好,登錄后才能下訂單哦!
這篇文章主要介紹python源碼剖析之PyObject的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
Python中一切皆是對(duì)象。
————Guido van Rossum(1989)
這句話只要你學(xué)過(guò)python,你就很有可能在你的Python學(xué)習(xí)之旅的前30分鐘就已經(jīng)見(jiàn)過(guò)了,但是這句話具體是什么意思呢?
一句話來(lái)說(shuō),就是面向?qū)ο笾械摹邦?lèi)”和“對(duì)象”在Python中都是對(duì)象。類(lèi)似于int對(duì)象的類(lèi)型對(duì)象,實(shí)現(xiàn)了“類(lèi)的概念”,對(duì)類(lèi)型對(duì)象“實(shí)例化”得到的實(shí)例對(duì)象實(shí)現(xiàn)了“對(duì)象”這個(gè)概念。
通常的說(shuō)法是,對(duì)象是數(shù)據(jù)以及基于這些數(shù)據(jù)的操作的集合。在計(jì)算機(jī)上,一個(gè)對(duì)象實(shí)際上就是一片被分配的內(nèi)存空間,這些內(nèi)存可能是連續(xù)的,也有可能是離散的,這都不重要,重要的是這片內(nèi)存在更高的層次上可以作為一個(gè)整體來(lái)考慮,這個(gè)整體就是一個(gè)對(duì)象。在這片內(nèi)存中,存儲(chǔ)著一系列的數(shù)據(jù)以及可以對(duì)這些數(shù)據(jù)進(jìn)行修改或讀取的一系列操作的代碼。
在 Python 中,對(duì)象就是在堆上申請(qǐng)的結(jié)構(gòu)體,對(duì)象不能是被靜態(tài)初始化的,并且也不能是在??臻g上生存的。唯一的例外就是類(lèi)型對(duì)象(type object),Python中所有的類(lèi)型對(duì)象都是被靜態(tài)初始化的。在 Python 中,一個(gè)對(duì)象一旦被創(chuàng)建,它在內(nèi)存中的大小就是不變的了。 這就意味著那些需要容納可變長(zhǎng)度數(shù)據(jù)的對(duì)象只能在對(duì)象內(nèi)維護(hù)一個(gè)指向一個(gè)可變大小的內(nèi)存區(qū)域的指針。
PyObject
和 PyVarObject
分別表示定長(zhǎng)對(duì)象和變長(zhǎng)對(duì)象,使用的C的struct
實(shí)現(xiàn)的,在結(jié)構(gòu)中分別只定義了 PyObject_HEAD
和 PyObject_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è)指向類(lèi)型對(duì)象PyTypeObject
結(jié)構(gòu)體的指針。因此, Python 中實(shí)際上對(duì)象機(jī)制的核心非常的簡(jiǎn)單,一個(gè)是引用計(jì)數(shù),一個(gè)就是類(lèi)型。并且Python中每一個(gè)對(duì)象的開(kāi)始字節(jié)都是相同的頭部,這使得對(duì)Python對(duì)象的引用十分統(tǒng)一,只需要一個(gè)PyObject*
可以引用任意一個(gè)對(duì)象。
這兩個(gè)結(jié)構(gòu)體定義的只是Python中對(duì)象共有的部分,其他的具體類(lèi)型會(huì)有額外的結(jié)構(gòu)體來(lái)定義,否則的話所有的對(duì)象豈不是都一樣了?比如int類(lèi)型的結(jié)構(gòu)體定義PyIntObject
中包含了PyObject_HEAD
和ob_ival
后者是一個(gè)long,存放具體的值。
那初始化對(duì)象的時(shí)候,去那里獲得對(duì)象的大小呢?只能是在類(lèi)型對(duì)象PyTypeObject
中了!類(lèi)型對(duì)象中存放了大量對(duì)象的元信息,大小顯然是一種和對(duì)象的類(lèi)型有關(guān)的元信息!注意,一個(gè)PyObject對(duì)象就是Python中對(duì)面向?qū)ο罄碚撝蓄?lèi)這個(gè)概念的實(shí)現(xiàn),這里面存放了類(lèi)型名、內(nèi)存空間、操作函數(shù)指針等信息。
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)
。另一種是類(lèi)型相關(guān)API(COL:Concrete Object Layer),只能應(yīng)用于具體類(lèi)型的對(duì)象上,比如PyInt_FromLong(10)
。
自定義對(duì)象在Python內(nèi)部不可能存在COL,所以只能根據(jù)其類(lèi)型對(duì)象來(lái)創(chuàng)建實(shí)例對(duì)象,這就需要PyTypeObject
中的tp_new
函數(shù)指針,如果是自定義對(duì)象,這個(gè)指針可能是空,那就通過(guò)PyTypeObject
的tp_base
找到類(lèi)型對(duì)象的基類(lèi),再找tp_new
指針,這個(gè)過(guò)程中會(huì)利用類(lèi)型對(duì)象中記錄的空間信息申請(qǐng)內(nèi)存。對(duì)于 Python 中的任何一種變長(zhǎng)對(duì)象,tp_itemsize
這個(gè)域是必須設(shè)置的,tp_itemsize
指明了由變長(zhǎng)對(duì)象保存的元素的單位長(zhǎng)度,所謂單位長(zhǎng)度即是指一個(gè)對(duì)象在內(nèi)存中的長(zhǎng)度。這個(gè) tp_itemsize
和ob_size
共同決定了應(yīng)該額外申請(qǐng)的內(nèi)存的總大小是多少。
內(nèi)建對(duì)象最終會(huì)使用COL完成創(chuàng)建工作。
new
函數(shù)完成后,會(huì)執(zhí)行init
函數(shù),前者類(lèi)似于new操作符,后者類(lèi)似于構(gòu)造函數(shù)。
像前面說(shuō)的,對(duì)象的行為被類(lèi)型對(duì)象中的函數(shù)指針?biāo)x。這些操作中,有三組非常重要的操作族:tp_as_number
、tp_as_sequence
、tp_as_mapping
分別指向PyNumberMethods
、PtSequenceMethods
、PyMappingMethods
函數(shù)族結(jié)構(gòu)體。所謂“鴨子類(lèi)型”,就行能找到該類(lèi)型對(duì)應(yīng)的操作,就可以當(dāng)做這個(gè)類(lèi)型來(lái)用。
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)通過(guò)int繼承得到的數(shù)值對(duì)象,通過(guò)重寫(xiě)魔術(shù)方法,使其支持了字典類(lèi)型的操作,其實(shí)我們可以認(rèn)為是,制定了MyInt這個(gè)類(lèi)型對(duì)象的tp_as_mapping.mp_subscript
操作。
之前說(shuō)了,作為類(lèi)的實(shí)現(xiàn)的類(lèi)型對(duì)象也是Python對(duì)象,那么類(lèi)型對(duì)象PyObject
的ob_type
指針指向哪呢?是指向自己?jiǎn)幔?strong>盡管我一開(kāi)始也是這么想的,但可惜這個(gè)答案不對(duì),類(lèi)型對(duì)象指向的對(duì)象是PyType_Type。這個(gè)對(duì)象在Python類(lèi)型機(jī)制中很重要,所有用戶自定義class的PyTypeObject
對(duì)象都是通過(guò)這個(gè)對(duì)象創(chuàng)建的,因此他是Python中的元類(lèi)(metaclass)。他是所有class的class。而元類(lèi)的類(lèi)型是自己,這里出現(xiàn)了我們一開(kāi)始認(rèn)為會(huì)出現(xiàn)的自己只想自己的情況!
i=1 class A: pass a=A() print(i.__class__) # 類(lèi)型對(duì)象 print(i.__class__.__class__) # 元類(lèi) print(a.__class__) # 類(lèi)型對(duì)象 print(a.__class__.__class__) # 元類(lèi) print(a.__class__.__class__.__class__) # 指向自己
留在這里的疑問(wèn):虛線和虛線指向的對(duì)象是啥玩?
通過(guò) PyObject 和類(lèi)型對(duì)象, Python 利用 C 語(yǔ)言完成了 C++所提供的繼承和多態(tài)的特性。一開(kāi)始已經(jīng)提到,Python中所有對(duì)象的前面幾個(gè)字節(jié)都是PyObject類(lèi)型也就是PyObject_HEAD
結(jié)構(gòu)體。因此在 Python 內(nèi)部各個(gè)函數(shù)之間傳遞的都是一種范型指針PyObject*
。這個(gè)指針?biāo)傅膶?duì)象究竟是什么類(lèi)型的,不知道,只能從指針?biāo)笇?duì)象的ob_type
域判斷,而正是通過(guò)這個(gè)域,Python 實(shí)現(xiàn)了多態(tài)機(jī)制。
真正執(zhí)行的時(shí)候,通過(guò)找到實(shí)例對(duì)象指向的類(lèi)型對(duì)象的函數(shù)指針來(lái)執(zhí)行方法。這里同一個(gè)函數(shù)在不同情況下表現(xiàn)出了不同的行為,這正是多態(tài)的核心所在。
在 Python 中,主要是通過(guò)Py_INCREF(op)
和Py_DECREF(op)
兩個(gè)宏來(lái)增加和減少一個(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)資源),即類(lèi)型對(duì)象中tp_dealloc
指向的函數(shù)。例外的是類(lèi)型對(duì)象,PyTypeObject
是超越引用計(jì)數(shù)規(guī)則的,永遠(yuǎn)不會(huì)被析構(gòu),每一個(gè)對(duì)象中指向類(lèi)型對(duì)象的指針不被視為對(duì)類(lèi)型對(duì)象的引用。
這有些觀察者模式(Observer)的影子,在ob_refcnt
減為 0 之后,將觸發(fā)對(duì)象銷(xiāo)毀的事件;從 Python 的對(duì)象體系來(lái)看,各個(gè)對(duì)象又提供了不同的事件處理函數(shù),而事件的注冊(cè)動(dòng)作正是在各個(gè)對(duì)象對(duì)應(yīng)的類(lèi)型對(duì)象中靜態(tài)完成的。
在PyObject
中我們看到ob_refcnt
是一個(gè) 32 位的整形變量,這實(shí)際是一個(gè)Python所做的假設(shè),即對(duì)一個(gè)對(duì)象的引用不會(huì)超過(guò)一個(gè)整形變量的最大值。
1、云計(jì)算,典型應(yīng)用OpenStack。2、WEB前端開(kāi)發(fā),眾多大型網(wǎng)站均為Python開(kāi)發(fā)。3.人工智能應(yīng)用,基于大數(shù)據(jù)分析和深度學(xué)習(xí)而發(fā)展出來(lái)的人工智能本質(zhì)上已經(jīng)無(wú)法離開(kāi)python。4、系統(tǒng)運(yùn)維工程項(xiàng)目,自動(dòng)化運(yùn)維的標(biāo)配就是python+Django/flask。5、金融理財(cái)分析,量化交易,金融分析。6、大數(shù)據(jù)分析。
以上是“python源碼剖析之PyObject的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。