Python源码剖析-深度探索动态语言核心技术
Python源碼剖析-深度探索動態(tài)語言核心技術(shù)
- 內(nèi)容簡介
- Python 總體架構(gòu)
- Python源代碼的組織
- 第一部分:Python內(nèi)建對象
- 第1章:Python對象初探
- 1.1 Python內(nèi)的對象
- 1.1.1 對象的基石-----PyObject
- 1.1.2 定長對象
- 重要點總結(jié)
- 1.2 類型對象
- 1.2.1 對象的創(chuàng)建
- 1.2.2 對象的行為
- 1.2.3 類型的類型
- 1.3 Python對象的多態(tài)性
- 1.4 引用計數(shù)
- 1.5 Python 對象的分類
- 第2章:Python中的整數(shù)對象
- 2.1 初識 PyIntObject 對象
- 2.2 PyIntObject 對象的創(chuàng)建和維護(hù)
- 2.2.1 對象創(chuàng)建的3種途徑
內(nèi)容簡介
為了更好地利用python語言,無論是python本身還是和C/C++配合使用,深刻理解python的運行原理都是非常重要的,本文以CPython源碼為研究對象,深入剖析Python的實現(xiàn)。主要包含:
- Python內(nèi)建對象
- Python虛擬機(jī)
- Python高級特性
本文參考: Python源碼剖析一書
學(xué)習(xí)建議:唯有親身嘗試,才能深解其中三昧。 在真實的源碼和文章的描述相比較揣摩,動手搗鼓搗鼓Python的源碼,用真實的輸出來驗證文章描述和自己的理解。
Python 總體架構(gòu)
首先我們應(yīng)該了解python的整體架構(gòu),對python 有個宏觀的認(rèn)識。
Python整體架構(gòu)分為三部分,如下圖:
- 左邊是python提供的大量模塊,庫,以及用戶自定義模塊
- 右邊是python的運行時環(huán)境,包括對象/類型系統(tǒng), 內(nèi)存分配器, 運行時狀態(tài)信息。
- 中間部分為解釋器(虛擬機(jī)), 包括詞法分析,語法分析,編譯器與 (虛擬機(jī)Code Evauator)
Python源代碼的組織
獲取源碼網(wǎng)站: 源碼網(wǎng)站
解壓后我們將看到目錄結(jié)構(gòu):
- Includes : 該目錄包含了python提供的所有頭文件,我們?nèi)绻胏、c++編寫自定義模塊擴(kuò)展python,就需要用到這里提供的頭文件
- Lib:包含了python自帶的所有標(biāo)準(zhǔn)庫, lib 中的庫都是用python編寫而成
- Modules: 該模塊包含了所有用C語言編寫的模塊, 比如random,cstringIO等,其中模塊都是那些對速度要求非常嚴(yán)格的模塊, (對速度沒有嚴(yán)格要求的放在了lib中)
- Parser: 包含了python解釋器中的詞法分析Scanner和語法分析 Parser部分
- Objects: 改目錄中包含了所有Python的內(nèi)建對象,包括整數(shù),list, dict等, 同時包含了Python在運行時需要的所有的內(nèi)部使用對象的實現(xiàn)。
- Python:是Python解釋器的 Compiler 和執(zhí)行引擎部分,是其運行的核心所在。
第一部分:Python內(nèi)建對象
第1章:Python對象初探
我們熟知在面向?qū)ο罄碚撝械?“類” 和 “對象” 這兩個概念在python中都是使用Python內(nèi)對象來實現(xiàn)的,也可以理解為一切都是對象, 于是我們將會帶著一些疑問進(jìn)入本章~
額外一些有意思的相關(guān)知識:
- 在Python中,對象是C中結(jié)構(gòu)體在堆上申請的一塊內(nèi)存,因此對象不能被靜態(tài)初始化,也不能在棧上生存,例外是(Python的類型對象type,都是被靜態(tài)初始化的 ~)
- 在Python中,一個對象一旦被創(chuàng)建,其內(nèi)存大小就是不變的了,于是python在對象內(nèi)維護(hù)一個指向一塊可變大小的內(nèi)存區(qū)域的指針來容納可變長度數(shù)據(jù)的對象,當(dāng)然這也是因為遵循這樣的規(guī)則是的通過指針維護(hù)對象的工作變得簡單。(struct _typeobject *ob_type)
1.1 Python內(nèi)的對象
1.1.1 對象的基石-----PyObject
所有的對象都擁有一些相同的內(nèi)容, 這些內(nèi)容就在PyObject中定義, PyObject是整個Python對象體系的核心。
而PyObject的秘密就在這個PyObject_HEAD中~
我們發(fā)現(xiàn),其實在PyObject的定義中, 僅有兩個東西:
- int (py_ssize_t) 類型的 ob_refcnt , 對象引用計數(shù)(垃圾回收機(jī)制)
- struct _typeobject *ob_type, 一個指針,來維護(hù)一個類型信息結(jié)構(gòu)(后續(xù)會再次分析)
PyObject中定義了每一個Python對象都必須有的內(nèi)容, 每一個Python對象除了擁有PyObject外,還會占據(jù)一些額外的內(nèi)存,保存屬于自己的特殊信息,比如 intobject就會多出一個 ob_ival 來表示其值。
1.1.2 定長對象
對于數(shù)組,這種 n 個 元素構(gòu)成的東西也是一類Python對象的共同特征, 因此, 在PyObject對象之外
還有一個表示這類對象的結(jié)構(gòu)體–PyVarObject
變長對象往往都是容器, ob_size 指明了所容納元素的個數(shù)
重要點總結(jié)
從PyObject_VAR_HEAD的定義中我們發(fā)現(xiàn), PyVarObject實際上只是對PyObject的擴(kuò)展而已,其開始部分的字節(jié)的意義和 PyObject相同, 一個引用計數(shù)加上一個類型信息結(jié)構(gòu)指針,這意味著在Python中對對象的引用變得十分的統(tǒng)一, 使用 PyObject* 指針能引用任意的一個對象。
不同的Python對象在內(nèi)存布局上的關(guān)系1.2 類型對象
在上文我們看到了Python中所有對象的共有信息的定義,但我們會思考,我們所創(chuàng)建的對象的真實描述信息在哪呢? 例如:Int 和 Str 對象占有的空間信息在哪~, 其實這些信息都被隱含在 PyObject 的 _typeobjct 指針指向的地方。
在_typeobjct 的定義中包含了很多的信息,主要分為4類:
- 類型名
- 創(chuàng)建該類型時分配的內(nèi)存空間大小信息 (tp_basicsize 和 tp_itemsize)
- 與該類型對象相關(guān)聯(lián)的操作信息(諸如 tp_print這樣的許多的函數(shù)指針)
- 類型的類型信息
事實上, 一個 PyTypeObject對象就是 Python中對面向?qū)ο罄碚撝小邦悺边@個概念的實現(xiàn),由于PyTypeObject是一個篇幅較大的話題,我們在第二部分來介紹構(gòu)建在PyTypeObject之上的Python的類型和對象體系。
1.2.1 對象的創(chuàng)建
思考: Python內(nèi)部究竟如何才能從無到有創(chuàng)建一個整數(shù)對象呢?
Python對外提供了C API,分為兩種:
- AOL,(Abstract Object Layer),形式如 PyObject_***形式, 可以應(yīng)用在任何Python對象上
- COL (Concrete Object Layer) 只能作用于某一種類型的對象上,對于內(nèi)建對象都有一套API
對于自定義的類型,比如 Class A(object) 定義的類型A,要創(chuàng)建其對象,由于Python不可能事先提供
PyA_New這樣的API, 他將會通過A所對應(yīng)的類型對象 來創(chuàng)建實例對象。
下面我們舉例創(chuàng)建整數(shù)對象的函數(shù)調(diào)用流程(如圖):
- PyInt_Type 中的 tp_new 會被調(diào)用,如果tp_new 是空,會到基類找tp_new
- tp_new會訪問PyInt_Type中記錄的 tp_basicsize 信息,完成申請內(nèi)存的操作
- 之后調(diào)用 tp_init ,完成初始化的操作
tp_new, tp_init 對應(yīng) new操作符和類的構(gòu)造函數(shù)
1.2.2 對象的行為
對象的行為是通過內(nèi)置大量函數(shù)指針來實現(xiàn)的,這些函數(shù)指針就表現(xiàn)了類型對象所定義的操作(行為)。
同時,在PyTypeObject有三個重要的操作族需要介紹一下:
tp_as_number, tp_as_sequence, tp_as_mapping,
分別指向 PyNumberMethods, PySequenceMethods 和 PyMappingMethods 函數(shù)族。
這里我們以序列操作族為例子:
也可以說當(dāng) tp_as_sequence 指針不為空時(list,str),表現(xiàn)出的行為就是序列行為。
1.2.3 類型的類型
在我們的PyTypeObject定義的最開始也會存在 PyObject_Var_HEAD, 證明Python中的類型本身也是一個對象,其類型是 PyType_Type:
- PyType_Type 在 Python的類型機(jī)制是非常關(guān)鍵的,所有用戶自定義Class所對應(yīng)的 PyTypeObject對象都是通過這個對象創(chuàng)建的。
這里我們來看一下Int類型的定義,它會調(diào)用 PyObject_HEAD_INIT這個宏來初始化公共的頭部分:
本質(zhì)上就是將 ob_type 指向 PyType_Type, 并將其引用計數(shù)設(shè)置為1
現(xiàn)在我們可以想象一個整數(shù)對象在運行時的形象表示:
1.3 Python對象的多態(tài)性
Python利用C語言實現(xiàn)了對象的多態(tài)性,Python內(nèi)部在創(chuàng)建對象時會使用 PyObject * 取保存和維護(hù)這個對象,(所有對象的頭部是相同的),因此直接可以使用該指針?biāo)笇ο蟮?ob_type 域動態(tài)去判斷,正是這個域的存在,Python實現(xiàn)了多態(tài)性。
我們來分析一下:
void Print(PyObject* object) {object->ob_type.tp_print(object); }如果指針本身是一個PyIntObject* ,就會調(diào)用到 PyIntObject的類型對象中定義的輸出操作,
如果是一個PyStringObject*, 就會調(diào)用到 PyStringObject 對象對應(yīng)的類型對象中定義的輸出操作。
1.4 引用計數(shù)
Python內(nèi)建了垃圾回收機(jī)制,進(jìn)行較為繁重的內(nèi)存管理工作,引用計數(shù)正是Python垃圾回收機(jī)制的一部分。
- Python中每一個東西都有一個 ob_refcnt 變量,維護(hù)著引用計數(shù),決定著對象的創(chuàng)建和消亡。
- 通過 Py_INCREF(op) 和 Py_DECREF(op) 兩個宏來增加和減少一個對象的引用計數(shù)。
- 當(dāng)引用計數(shù)為0,會調(diào)用該對象的 tp_dealloc 進(jìn)行析構(gòu)動作
注意: 析構(gòu)函數(shù)并不意味著最終會釋放內(nèi)存, 頻繁申請和釋放會有效率上的問題,因此Python中大量采用了內(nèi)存池的技術(shù)。
1.5 Python 對象的分類
我們將 Python 對象從概念上大致分為5類:
- Fundamental 對象: 類型對象
- Numeric 對象: 數(shù)值對象
- Sequence對象:容納其他對象的序列集合對象
- Mapping對象:關(guān)聯(lián)對象
- Internal對象: Python 虛擬機(jī)在運行時內(nèi)部使用的對象
第2章:Python中的整數(shù)對象
2.1 初識 PyIntObject 對象
在定義上,是對 c 語言 long 的擴(kuò)展而已~
對于其 ob_type 的指向,則是指向了 PyInt_Type
在PyInt_Type 中保存了關(guān)于PyIntObject對象的豐富信息,不僅有其對象應(yīng)占有的內(nèi)存大小,文檔信息,也包括了支持的操作。
操作定義: 需要注意的是 int_as_number 這個域,他是一個PyNumberMethods對象,PyNumberMethods 有39個函數(shù)指針,定義了39種可選的操作(加減乘除),而對于 int_as_number 確定了對于一個整數(shù)對象,數(shù)值操作是如何進(jìn)行的。
小知識點: 在整數(shù)的相加 int_add 中檢查了加法結(jié)果是否溢出,用了位運算。
原理:只有兩個相同符號的整數(shù)相加時才會溢出, 一正一負(fù)相加不會溢出, 溢出后得到的結(jié)果符號一定與任意一個整數(shù)符號相反,即
2.2 PyIntObject 對象的創(chuàng)建和維護(hù)
2.2.1 對象創(chuàng)建的3種途徑
內(nèi)建類型對象的tp_new, tp_init 操作來創(chuàng)建實例對象, 最終依舊是會調(diào)用Python為特定內(nèi)建對象準(zhǔn)備的
CAPI。 為了創(chuàng)建一個 PyIntObject對象,Python提供了3條途徑。
總結(jié)
以上是生活随笔為你收集整理的Python源码剖析-深度探索动态语言核心技术的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ 3090 Visible Lat
- 下一篇: python源码剖析-笔记2