詳解 Python 源碼之對(duì)象機(jī)制
本篇文章主要是對(duì)Python 進(jìn)行詳解,內(nèi)容是介紹Python 源碼之對(duì)象機(jī)制,先來(lái)看內(nèi)容。
1、對(duì)象
在Python的世界中,一切都是對(duì)象,一個(gè)整數(shù)是一個(gè)對(duì)象,一個(gè)字符串也是一個(gè)對(duì)象,更為奇妙的是,類型也是一個(gè)對(duì)象,整數(shù)類型是一個(gè)對(duì)象,字符串類型也是一個(gè)對(duì)象。從1980年Guido在那個(gè)圣誕節(jié)揭開Python世界的大幕開始,一直到現(xiàn)在,Python經(jīng)歷了一次一次的升級(jí),但是其實(shí)現(xiàn)語(yǔ)言一直都是ANSI C。我們知道,C并不是一個(gè)面向?qū)ο蟮恼Z(yǔ)言,那么在Python中,它的對(duì)象機(jī)制是如何實(shí)現(xiàn)的呢?
對(duì)于人的思維來(lái)說(shuō),對(duì)象是一個(gè)比較形象的概念,而對(duì)于計(jì)算機(jī)來(lái)說(shuō),對(duì)象實(shí)際上是一個(gè)抽象的概念。計(jì)算機(jī)并不能理解這是一個(gè)整數(shù),那是一個(gè)字符串,對(duì)于計(jì)算機(jī)來(lái)說(shuō),它所知道的一切都是字節(jié)。通常的說(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上生存的。唯一的例外就是類型對(duì)象(type object),Python中所有的類型對(duì)象都是被靜態(tài)初始化的。
在Python中,一個(gè)對(duì)象一旦被創(chuàng)建,它在內(nèi)存中的大小就是不變的了。這就意味著那些需要容納可變長(zhǎng)度數(shù)據(jù)的對(duì)象只能在對(duì)象內(nèi)維護(hù)一個(gè)指向一個(gè)可變大小的內(nèi)存區(qū)域的指針。為什么要設(shè)定這樣一條特殊的規(guī)則呢,因?yàn)樽裱@樣的規(guī)則可以使通過(guò)指針維護(hù)對(duì)象的工作變得非常的簡(jiǎn)單。因?yàn)橐坏┰试S對(duì)象的大小可在運(yùn)行期改變,我們可以考慮如下的情形。在內(nèi)存中有對(duì)象A,并且其后緊跟著對(duì)象B。如果運(yùn)行期某個(gè)時(shí)刻,A的大小增大了,這意味著必須將整個(gè)A移動(dòng)到內(nèi)存中的其他位置,否則A增大的部分將覆蓋原本屬于B的數(shù)據(jù)。一旦將A移動(dòng)到內(nèi)存中的其他位置,那么所有指向A的指針必須立即得到更新,光是想一想,就知道這樣的工作是多么的恐怖。
在Python中,所有的東西都是對(duì)象,而所有的對(duì)象都擁有一些相同的內(nèi)容,這些內(nèi)容在PyObject中定義,PyObject是整個(gè)Python對(duì)象機(jī)制的核心。
- [object.h]
- typedef struct _object {
- PyObject_HEAD
- } PyObject;
實(shí)際上,PyObject是Python中不包含可變長(zhǎng)度數(shù)據(jù)的對(duì)象的基石,而對(duì)于包含可變長(zhǎng)度數(shù)據(jù)的對(duì)象,它的基石是PyVarObject:
- [object.h]
- typedef struct { PyObject_VAR_HEAD} PyVarObject;
這兩個(gè)結(jié)構(gòu)體構(gòu)成了Python對(duì)象機(jī)制的核心基石,從代碼中我們可以看到,Python的對(duì)象的秘密都隱藏在PyObject_HEAD與PyObject_VAR_HEAD中。
- [object.h]
- #ifdef Py_TRACE_REFS
- /* Define pointers to support a doubly-linked list of all live heap objects. */
- #define _PyObject_HEAD_EXTRA \
- struct _object *_ob_next; \
- struct _object *_ob_prev;
- #define _PyObject_EXTRA_INIT 0, 0,#else#define _PyObject_HEAD_EXTRA#define _PyObject_EXTRA_INIT#endif
- /* 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 */
在PyObject_HEAD中定義了每一個(gè)Python對(duì)象都必須有的內(nèi)容,這些內(nèi)容將出現(xiàn)在每一個(gè)Python對(duì)象所占有的內(nèi)存的最開始的字節(jié)中,從PyObject_VAR_HEAD的定義可以看出,即使對(duì)于擁有可變大小數(shù)據(jù)的對(duì)象,其最開始的字節(jié)也含有相同的內(nèi)容,這就是說(shuō),在Python中,每一個(gè)對(duì)象都擁有相同的對(duì)象頭部。這就使得在Python中,對(duì)對(duì)象的引用變得非常的統(tǒng)一,我們只需要用一個(gè)PyObject *就可以引用任意的一個(gè)對(duì)象,而不論該對(duì)象實(shí)際是一個(gè)什么對(duì)象。
在PyObject_HEAD的定義中,我們注意到有一個(gè)ob_refcnt的整形變量,這個(gè)變量的作用是實(shí)現(xiàn)引用計(jì)數(shù)機(jī)制。對(duì)于某一個(gè)對(duì)象A,當(dāng)有一個(gè)新的PyObject *引用該對(duì)象時(shí),A的引用計(jì)數(shù)應(yīng)該增加;而當(dāng)這個(gè)PyObject *被刪除時(shí),A的引用計(jì)數(shù)應(yīng)該減少。當(dāng)A的引用計(jì)數(shù)減少到0時(shí),A就可以從堆上被刪除,以釋放出內(nèi)存供別的對(duì)象使用。
在PyObject_HEAD中,我們注意到ob_type是一個(gè)指向_typeobject結(jié)構(gòu)體的指針,那么這個(gè)結(jié)構(gòu)體是一個(gè)什么東西呢?實(shí)際上這個(gè)結(jié)構(gòu)體也是一個(gè)對(duì)象,它是用來(lái)指定一個(gè)對(duì)象類型的類型對(duì)象。這個(gè)類型對(duì)象我們將在后邊詳細(xì)地考察?,F(xiàn)在我們看到了,在Python中實(shí)際上對(duì)象機(jī)制的核心非常的簡(jiǎn)單,一個(gè)是引用計(jì)數(shù),一個(gè)就是類型。
而對(duì)于擁有可變長(zhǎng)度數(shù)據(jù)的對(duì)象,這樣的對(duì)象通常都是容器,我們可以在PyObject_VAR_HEAD中看到ob_size這個(gè)變量,這個(gè)變量實(shí)際上就是指明了該對(duì)象中一共包含了多少個(gè)元素。注意,ob_size指明的是元素的個(gè)數(shù),而不是字節(jié)的數(shù)目。比如對(duì)于Python中最常用的list,它就是一個(gè)PyVarObject對(duì)象,如果某一時(shí)刻,這個(gè)list中有5個(gè)元素,那么PyVarObject.ob_size的值就是5。
#p#
2、類型對(duì)象
在上面的描述中,我們看到了Python中所有對(duì)象的對(duì)象頭的定義。所以,當(dāng)內(nèi)存中存在某一個(gè)Python的對(duì)象時(shí),該對(duì)象的開始的幾個(gè)字節(jié)的含義一定會(huì)符合我們的預(yù)期。但是,當(dāng)我們把眼光沿著時(shí)間軸上溯,就會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題。當(dāng)在內(nèi)存中分配空間,創(chuàng)建對(duì)象的時(shí)候,毫無(wú)疑問(wèn)地,必須要知道申請(qǐng)多大的空間。顯然,這不會(huì)是一個(gè)定值,因?yàn)閷?duì)于不同的對(duì)象,需要不同的空間,一個(gè)整數(shù)對(duì)象和一個(gè)字符串對(duì)象所需的空間肯定不同。那么,對(duì)象所需的內(nèi)存空間的大小的信息到底在哪里呢?在對(duì)象頭中顯然沒有這樣的信息。
實(shí)際上,內(nèi)存空間大小這樣的對(duì)象的元信息是與對(duì)象所屬類型密切相關(guān)的,因此它一定會(huì)出現(xiàn)在與對(duì)象所對(duì)應(yīng)的類型對(duì)象中?,F(xiàn)在我們可以來(lái)詳細(xì)考察一下類型對(duì)象_typeobject:
- [object.h]
- typedef struct _typeobject {
- PyObject_VAR_HEAD char *tp_name;
- /* For printing, in format "<module>.<name>" */
- int tp_basicsize, tp_itemsize;
- /* For allocation */
- /* Methods to implement standard operations */
- destructor tp_dealloc;printfunc tp_print;
- ……
- /* More standard operations (here for binary compatibility) */
- hashfunc tp_hash;
- ternaryfunc tp_call;
- ……
- }
- PyTypeObject;
在_typeobject的定義中包含了許多的信息,主要可以分為四類:
1、類型名,tp_name,主要是Python內(nèi)部以及調(diào)試的時(shí)候使用;
2、創(chuàng)建該類型對(duì)象是分配內(nèi)存空間的大小的信息,即tp_basicsize和tp_itemsize;
3、與該類型對(duì)象相關(guān)聯(lián)的操作信息,比如hashfunc,tp_hash就指明對(duì)于該類型的對(duì)象,如何生成其hash值。在Object.h中可以看到,hashfunc實(shí)際上是一個(gè)函數(shù)指針:typedef long (*hashfunc)(PyObject *); 在_typeobject中,包含了大量的函數(shù)指針,這些函數(shù)指針將用來(lái)指定某個(gè)類型的操作信息。這些操作主要分為標(biāo)準(zhǔn)操作(dealloc, print, compare),標(biāo)準(zhǔn)操作族(numbers, sequences, mappings),以及其他操作(hash, buffer, call…)。
4、我們?cè)谙逻厡⒁枋龅念愋偷念愋托畔ⅰ?/p>
有趣的是我們?cè)赺typeobject的頭部發(fā)現(xiàn)了PyObject_VAR_HEAD,這意味著類型實(shí)際上也是一個(gè)對(duì)象。我們知道在Python中,每一個(gè)對(duì)象都是對(duì)應(yīng)一種類型的,那么一個(gè)有趣的問(wèn)題就出現(xiàn)了,類型對(duì)象的類型是什么呢?這個(gè)問(wèn)題聽上去很繞口,實(shí)際上確非常重要,對(duì)于其他的對(duì)象,可以通過(guò)與其關(guān)聯(lián)的類型對(duì)象確定其類型,那么通過(guò)什么來(lái)確定一個(gè)對(duì)象是類型對(duì)象呢?答案就是PyType_Type:
- [typeobject.c]
- PyTypeObject PyType_Type = {
- PyObject_HEAD_INIT(&PyType_Type) 0,
- /* ob_size */ "type",
- /* tp_name */ sizeof(PyHeapTypeObject),
- /* tp_basicsize */ sizeof(PyMemberDef),
- /* tp_itemsize */ …… PyObject_GC_Del,
- /* tp_free */ (inquiry)type_is_gc,
- /* tp_is_gc */};
前面提到,在Python中,每一個(gè)對(duì)象它的開始部分都是一樣的。每一個(gè)對(duì)象都將自己的引用計(jì)數(shù),類型信息保存在開始的部分中。為了方便對(duì)這部分內(nèi)存的初始化,Python中提供了幾個(gè)有用的宏:
- [object.h]#ifdef Py_TRACE_REFS#define _PyObject_EXTRA_INIT 0, 0,#else#define _PyObject_EXTRA_INIT#endif#define PyObject_HEAD_INIT(type) \
- _PyObject_EXTRA_INIT \
- 1, type,
再回顧一下PyObject和PyVarObject的定義,初始化的動(dòng)作就一目了然了。實(shí)際上,這些宏在類型對(duì)象的初始化中被大量地使用著。
如果以一個(gè)整數(shù)對(duì)象為例,可以更清晰地看到一半的類型對(duì)象和這個(gè)特立獨(dú)行的PyType_Type對(duì)象之間的關(guān)系:
- [intobject.c]
- PyTypeObject PyInt_Type = {
- PyObject_HEAD_INIT(&PyType_Type) 0,
- "int",
- sizeof(PyIntObject),
- ……
- };
現(xiàn)在我們可以放飛想象,看到一個(gè)整數(shù)對(duì)象在運(yùn)行時(shí)的抽象的表示了,下圖中的箭頭表示ob_type:
#p#
3、對(duì)象間的繼承和多態(tài)
通過(guò)PyObject和類型對(duì)象,Python利用C語(yǔ)言完成了C++所提供的繼承和多態(tài)的特性。前面提到,在Python中所有的內(nèi)建對(duì)象(PyIntObject等)和內(nèi)部使用對(duì)象(PyCodeObject等)的最開始的內(nèi)存區(qū)域都擁有一個(gè)PyObject。實(shí)際上,這一點(diǎn)可以視為PyIntObject,PyCodeObject等對(duì)象都是從PyObject繼承而來(lái)。
在Python創(chuàng)建一個(gè)對(duì)象,比如PyIntObject對(duì)象時(shí),會(huì)分配內(nèi)存,進(jìn)行初始化。然后這個(gè)對(duì)象會(huì)由一個(gè)PyObject*變量來(lái)維護(hù),而不是通過(guò)一個(gè)PyIntObject*指針來(lái)維護(hù)。其它對(duì)象也與此類似,所以在Python內(nèi)部各個(gè)函數(shù)之間傳遞的都是一種范型指針PyObject*。這個(gè)指針?biāo)傅膶?duì)象究竟是什么類型的,不知道,只能從指針?biāo)笇?duì)象的ob_type域判斷,而正是通過(guò)這個(gè)域,Python實(shí)現(xiàn)了多態(tài)機(jī)制。
考慮下面的代碼:
- void Print(PyObject* object)
- {
- object->ob_type->tp_print(object);
- }
如果傳給Print的指針實(shí)際是一個(gè)PyIntObject*,那么就會(huì)調(diào)用PyIntObject對(duì)象對(duì)應(yīng)的類型對(duì)象中定義的輸出操作,如果傳給Print的指針實(shí)際是一個(gè)PyStringObject*,那么就會(huì)調(diào)用PyStringObject對(duì)象對(duì)應(yīng)的類型對(duì)象中定義的輸出操作??梢钥吹?,這里同一個(gè)函數(shù)在不同情況下表現(xiàn)出了不同的行為,這正是多態(tài)的核心所在。
在object.c中,Python實(shí)現(xiàn)了一些對(duì)于類型對(duì)象中的各種操作的簡(jiǎn)單包裝,從而為Python運(yùn)行時(shí)提供了一個(gè)統(tǒng)一的多態(tài)接口層:
- [object.c]
- long PyObject_Hash(PyObject *v)
- {
- PyTypeObject *tp = v->ob_type;
- if (tp->tp_hash != NULL)
- return (*tp->tp_hash)(v);
- ……
- }
4、引用計(jì)數(shù)
在C或C++中,程序員被賦予了極大的自由,可以任意地申請(qǐng)內(nèi)存。但是權(quán)利的另一面則對(duì)應(yīng)著責(zé)任,程序員必須自己負(fù)責(zé)將申請(qǐng)的內(nèi)存釋放,并釋放無(wú)效指針??梢哉f(shuō),這一點(diǎn)正是萬(wàn)惡之源,大量的內(nèi)存泄露和懸空指針的bug由此而生,如黃河泛濫一發(fā)不可收拾 :)
現(xiàn)代的開發(fā)語(yǔ)言中一般都選擇由語(yǔ)言本身負(fù)責(zé)內(nèi)存的管理和維護(hù),即采用了垃圾收集機(jī)制,比如Java和C#。垃圾收集機(jī)制使開發(fā)人員從維護(hù)內(nèi)存分配和清理的繁重工作中解放出來(lái),但同時(shí)也剝奪了程序員與內(nèi)存親密接觸的機(jī)會(huì),并付出了一定的運(yùn)行時(shí)效率作為代價(jià)。現(xiàn)在看來(lái),隨著垃圾收集機(jī)制的完善,對(duì)時(shí)間要求不是非常高的程序完全可以通過(guò)使用垃圾收集機(jī)制的語(yǔ)言來(lái)完成,這部分程序占了這個(gè)星球上大多數(shù)的程序。這樣做的好處是提高了開發(fā)效率,并降低了bug發(fā)生的機(jī)率。Python同樣也內(nèi)建了垃圾收集機(jī)制,代替程序員進(jìn)行繁重的內(nèi)存管理工作,而引用計(jì)數(shù)正式Python垃圾收集機(jī)制的一部分。
Python通過(guò)對(duì)一個(gè)對(duì)象的引用計(jì)數(shù)的管理來(lái)維護(hù)對(duì)象在內(nèi)存中的生存。我們知道在Python中每一個(gè)東西都是一個(gè)對(duì)象,都有一個(gè)ob_refcnt變量,正是這個(gè)變量維護(hù)著該對(duì)象的引用計(jì)數(shù),從而也最終決定著該對(duì)象的生生滅滅。
在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)來(lái)釋放該對(duì)象所占有的內(nèi)存和系統(tǒng)資源。注意這里的析構(gòu)函數(shù)借用了C++的詞匯,實(shí)際上這個(gè)析構(gòu)動(dòng)作是通過(guò)在對(duì)象對(duì)應(yīng)的類型對(duì)象中定義的一個(gè)函數(shù)指針來(lái)刻畫的,還記得嗎?就是那個(gè)tp_dealloc。
如果熟悉設(shè)計(jì)模式中Observer模式,可以看到,這里隱隱約約透著Observer模式的影子。在ob_refcnt減為0之后,將觸發(fā)對(duì)象銷毀的事件;從Python的對(duì)象體系來(lái)看,各個(gè)對(duì)象又提供了不同的事件處理函數(shù),而事件的注冊(cè)動(dòng)作正是在各個(gè)對(duì)象對(duì)應(yīng)的類型對(duì)象中靜態(tài)完成的。
對(duì)于這兩個(gè)宏的參數(shù)op來(lái)說(shuō),不允許op是一個(gè)指向空對(duì)象的指針(NIL),如果op是一個(gè)NIL,那么必須使用Py_XINCREF/Py_XDECREF這一對(duì)宏。
在PyObject中我們看到ob_refcnt是一個(gè)32位的整形變量,這實(shí)際是一個(gè)Python所做的假設(shè),即對(duì)一個(gè)對(duì)象的引用不會(huì)超過(guò)一個(gè)整形變量的最大值。一般情況下,如果不是惡意代碼,這個(gè)假設(shè)顯然是不會(huì)被突破的。
需要注意的是,在Python的各種對(duì)象中,類型對(duì)象是超越引用計(jì)數(shù)規(guī)則的。類型對(duì)象“跳出三界外,不再五行中”,永遠(yuǎn)不會(huì)被析構(gòu)。每一個(gè)對(duì)象中指向類型對(duì)象的指針不被視為對(duì)類型對(duì)象的引用。
在每一個(gè)對(duì)象創(chuàng)建的時(shí)候,Python提供了一個(gè)_Py_NewReference(op)宏來(lái)將對(duì)象的引用計(jì)數(shù)初始化為1。
在Python的源代碼中可以看到,在不同的編譯選項(xiàng)下(Py_REF_DEBUG, Py_TRACE_REFS),引用計(jì)數(shù)的宏還要做許多額外的工作。下面展示的代碼是Python在最終發(fā)行時(shí)這些宏所對(duì)應(yīng)的實(shí)際的代碼:
- [object.h]
- /* Without Py_TRACE_REFS, there's little enough to do that we expand code
- * inline.
- */
- #define _Py_NewReference(op) ((op)->ob_refcnt = 1)
- #define _Py_Dealloc(op) ((*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
- #define Py_INCREF(op) ((op)->ob_refcnt++)
- #define Py_DECREF(op) \
- if (--(op)->ob_refcnt != 0) \
- ; \
- else \
- _Py_Dealloc((PyObject *)(op))
- /* Macros to use in case the object pointer may be NULL: */
- #define Py_XINCREF(op) if ((op) == NULL) ; else Py_INCREF(op)
- #define Py_XDECREF(op) if ((op) == NULL) ; else Py_DECREF(op)
在一個(gè)對(duì)象的引用計(jì)數(shù)減為0時(shí),與該對(duì)象對(duì)應(yīng)的析構(gòu)函數(shù)就會(huì)被調(diào)用,但是要特別注意的是,調(diào)用析構(gòu)函數(shù)并不意味著最終一定會(huì)調(diào)用free釋放內(nèi)存空間,如果真是這樣的話,那頻繁地申請(qǐng)、釋放內(nèi)存空間會(huì)使Python的執(zhí)行效率大打折扣(更何況Python已經(jīng)多年背負(fù)了人們對(duì)其執(zhí)行效率的指責(zé):)。一般來(lái)說(shuō),Python中大量采用了內(nèi)存對(duì)象池的技術(shù),使用這種技術(shù)避免頻繁地申請(qǐng)和釋放內(nèi)存空間。因此在析構(gòu)時(shí),通常都是將對(duì)象占用的空間歸還到內(nèi)存池中。這一點(diǎn)在接下來(lái)對(duì)Python內(nèi)建對(duì)象的實(shí)現(xiàn)中可以看得一清二楚。
#p#
5、Python對(duì)象的分類
我們將Python的對(duì)象從概念上大致分為四類,需要指出的是,這種分類并不一定完全正確,不過(guò)是提供一種看待Python中對(duì)象的視角而已:
Math :數(shù)值對(duì)象
Container :容納其他對(duì)象的集合對(duì)象
Composition :表示程序結(jié)構(gòu)的對(duì)象
Internal :Python解釋器在運(yùn)行時(shí)內(nèi)部使用的對(duì)象
圖2列出了我們的對(duì)象分類體系,并給出了每一個(gè)類別中的一些實(shí)例:
6、通向Python之路
對(duì)Python源碼的剖析將分為四部分。
1.靜態(tài)對(duì)象剖析:首先我們會(huì)分析靜態(tài)的對(duì)象,Math對(duì)象和Container對(duì)象,深刻理解這些對(duì)象對(duì)我們理解Python解釋器的運(yùn)行會(huì)有很大的幫助,同時(shí),對(duì)我們編寫Python代碼也將大有裨益,在編寫Python代碼時(shí),你會(huì)清晰地意識(shí)到系統(tǒng)內(nèi)部這些對(duì)象將如何運(yùn)作,變化。當(dāng)然,我們并不會(huì)分析所有的Python對(duì)象,而是選取使用最頻繁的四種對(duì)象:PyIntObject, PyStringObject, PyListObject, PyDictObject進(jìn)行剖析。
2.運(yùn)行時(shí)剖析:在分析完靜態(tài)的對(duì)象之后,我們將進(jìn)入Python解釋器,在這里我們會(huì)詳細(xì)地考察Python的字節(jié)碼(byte code)以及解釋器對(duì)字節(jié)碼的解釋和執(zhí)行過(guò)程。這部分將完整地展現(xiàn)Python中所有的語(yǔ)法結(jié)構(gòu),如一般表達(dá)式,控制流,異常流,函數(shù),類等等的字節(jié)碼層面的實(shí)現(xiàn)細(xì)節(jié)。同時(shí),在這部分,我們會(huì)考察大部分的Python內(nèi)部對(duì)象。
3.編譯期剖析:這部分沒什么好打廣告的了,目標(biāo)明確,對(duì)象清晰,但是難度呢,絕不簡(jiǎn)單 :
4.運(yùn)行環(huán)境剖析:這部分將考察從激活Python到Python準(zhǔn)備就緒,可以接受用戶輸入或者執(zhí)行腳本文件,這段時(shí)間內(nèi),Python如何建立自己的運(yùn)行環(huán)境,并建立了怎樣的運(yùn)行環(huán)境,呵呵透露一下,想想Python那個(gè)龐大的builtin函數(shù)集合,這些就是這部分考察的重點(diǎn)。
閱讀完這些內(nèi)容之后,對(duì)于Python,你應(yīng)該是了如指掌了,在以后編寫Python代碼時(shí),你的腦子里甚至可以出現(xiàn)Python解釋器將如何一步步解釋你的代碼的情形。當(dāng)然,這只是我寫作本書的副產(chǎn)品。這本書誕生的真正原因只有一個(gè),興趣,我對(duì)Python的實(shí)現(xiàn)有濃厚的興趣。這本書也只是第一步,希望以后還能繼續(xù)對(duì)Python系列,如IronPython、Jython,PyPy的探索,當(dāng)然,對(duì)于其他動(dòng)態(tài)語(yǔ)言,比如Ruby的探索,我希望也會(huì)有時(shí)間去做。
小結(jié):詳解 Python 源碼之對(duì)象機(jī)制的內(nèi)容介紹完了,希望本文對(duì)你有幫助,更多關(guān)于Python 的內(nèi)容請(qǐng)參考編輯推薦。