為什么要看 Python 源碼?它的結(jié)構(gòu)長什么樣子?
楔子
毫無疑問,Python 已經(jīng)成為當(dāng)下最主流的語言之一,如果你只是會用,那么很難和其他人拉開差距。但如果你知道 Python 解釋器的底層原理,比如:
- 列表、字典、生成器等數(shù)據(jù)結(jié)構(gòu)是怎么實(shí)現(xiàn)的;
- GIL 如何限制多線程只能同時使用一個核;
- 虛擬機(jī)是如何執(zhí)行字節(jié)碼的;
- Python 的垃圾回收又是怎么一回事;
- ······
那么你在面試的時候一定能讓面試官眼前一亮,并且也能寫出更好、更優(yōu)雅的代碼,這也是我們?yōu)槭裁匆饰?Python 解釋器源碼???Python 解釋器的源碼行數(shù)有五十多萬行,該怎么入手呢?不用擔(dān)心,本系列就來抽絲剝繭,帶你近距離觀察 Python 解釋器這座宏偉大廈。
注:官方 Python 解釋器由 C 語言編寫,我們稱之為 CPython。想要讀懂它,需要有一定的 C 語言基礎(chǔ),當(dāng)然我也會給出詳細(xì)的注釋。
本系列力求詳細(xì)、精致,在介紹源碼時會給出大量的注釋和清晰的圖表,并且我不僅僅會介紹源碼實(shí)現(xiàn),還會穿插大量的 Python 普通知識。因?yàn)?Python 解釋器由 C 語言編寫,想要讀懂它,需要有一定的 C 語言基礎(chǔ)。而本系列則確保,不管你 C 語言的水平如何,讀了之后都能有所收獲。
下載 CPython
接下來登錄 Python 官網(wǎng) www.python.org 下載 CPython。
圖片
目前 Python 的最新版本是 3.12.3,我們點(diǎn)擊它。當(dāng)然隨著時間的推移,Python 也會進(jìn)行更新。
圖片
再點(diǎn)擊 Gzipped source tarball 即可下載指定版本的源碼。
CPython 源碼結(jié)構(gòu)
壓縮包下載下來之后解壓,即可得到整個 CPython 工程項(xiàng)目,我們看看它長什么樣子?
圖片
解釋一下每個目錄的作用。
Doc 目錄
存儲 Python 文檔的源文件(.rst),用于編譯之后生成官方文檔。
Grammar 目錄
負(fù)責(zé)定義 Python 的語法規(guī)則。
Include 目錄
包含 Python 所有公開的頭文件,這些文件定義了 Python 的 C API,在編寫擴(kuò)展模塊和嵌入式開發(fā)時會用到。
Lib 目錄
Python 的標(biāo)準(zhǔn)庫,對于那些不影響性能的功能會用 Python 編寫,然后放在 Lib 目錄下面。
Modules 目錄
Python 的內(nèi)置庫,這些庫都是用 C 編寫的,編譯之后會內(nèi)嵌在解釋器里面。我們舉個例子:
import random, _random
import re, _sre
import io, _io
import ast, _ast
以 random 為例,它是用來生成隨機(jī)數(shù)的,和性能密切相關(guān)。所以它的核心功能由 C 編寫,編譯之后內(nèi)嵌在解釋器里,模塊名為 _random。只不過 Python 又封裝了一個 random,在內(nèi)部會導(dǎo)入 _random,像 re 和 _sre、asyncio 和 _asyncio 都是類似的關(guān)系。
Modules 目錄里面實(shí)現(xiàn)了大量和性能相關(guān)的模塊,比如 sys、time、gc 等等,我們后續(xù)再聊。
Objects 目錄
包含 Python 內(nèi)置數(shù)據(jù)結(jié)構(gòu)的底層實(shí)現(xiàn),像字典、列表、元組、函數(shù)等,底層實(shí)現(xiàn)都定義在 Objects 目錄中。
Parser 目錄
負(fù)責(zé) Python 編譯器的具體實(shí)現(xiàn),雖然 Python 是解釋型語言,但也是要經(jīng)過編譯的。編譯的結(jié)果為 PyCodeObject 對象,它里面包含了要執(zhí)行的字節(jié)碼,編譯完之后會交給虛擬機(jī)執(zhí)行。
所以 Python 解釋器 = Python 編譯器 + Python 虛擬機(jī)。
Python 目錄
Python 虛擬機(jī)的具體實(shí)現(xiàn),字節(jié)碼的執(zhí)行、執(zhí)行環(huán)境的管理等都在里面。
Mac 目錄
用于 Mac OS X 平臺的特定工具和腳本。
Misc 目錄
包含各種雜項(xiàng)文件,如配置腳本、工具等。
PC 目錄
專為 Windows 平臺編寫的配置文件和特定擴(kuò)展。
PCbuild 目錄
用于在 Windows 上編譯 Python 的項(xiàng)目文件。
Programs 目錄
包含 Python 其它可執(zhí)行文件(如 IDLE)的源代碼。
Tools 目錄
包含用 Python 編寫的各種腳本和工具,幫助開發(fā)和維護(hù) Python。
以上就是 CPython 的源碼結(jié)構(gòu),對它有一個基本的認(rèn)識有助于我們后續(xù)的源碼學(xué)習(xí)。
解釋器、編譯器、虛擬機(jī)
介紹源碼結(jié)構(gòu)時我們說 Python 解釋器 = Python 編譯器 + Python 虛擬機(jī),那當(dāng)解釋器執(zhí)行 py 文件時都經(jīng)歷了哪些過程呢?
圖片
Read File、Scanner、Parser、Compiler 都是由 Python 編譯器負(fù)責(zé)的,Code Eval 則由 Python 虛擬機(jī)負(fù)責(zé)。
因此 Python 雖然是解釋型語言,但也有編譯的過程。源代碼會被編譯器編譯成 PyCodeObject 對象,然后再交給虛擬機(jī)來執(zhí)行。而之所以要存在編譯,是為了讓虛擬機(jī)能更快速地執(zhí)行,比如在編譯階段常量都會提前分配好,而且還可以盡早檢測出語法上的錯誤。
而 Python 編譯器和 Python 虛擬機(jī)組合起來,便是 Python 解釋器。
圖片
如果你了解 Java,那么應(yīng)該知道 Java 也有編譯器和虛擬機(jī)。只不過 Java 的編譯器和虛擬機(jī)是分開的,而 Python 則是整合在一起的。
不過在后續(xù)介紹 Python 源碼的時候,我們暫不涉及 Python 編譯器的部分,也就是 Parser 目錄里面的代碼不做分析,因?yàn)樯婕暗骄幾g原理。而且編譯這一過程也不是 Python 語言獨(dú)有的,任何一門編程語言、當(dāng)然還有 SQL 都會涉及到編譯。所以探究 Python 代碼的編譯過程沒太大意義,我們的重點(diǎn)是 Python 代碼的編譯結(jié)果,以及虛擬機(jī)是如何執(zhí)行的?
當(dāng)然如果大家對編譯過程感興趣,我們后面也會介紹一下這方面的內(nèi)容。舉個例子,我們來替換掉 Python 的幾個關(guān)鍵字。
圖片
Python 源碼的分詞,語法解析等均由 Parser 目錄負(fù)責(zé)。
圖片
比如 tokenizer.c 負(fù)責(zé)分詞,parser.c 負(fù)責(zé)語法解析,感興趣可以看一下,但不建議花太多時間。因?yàn)檫@個過程對深入 Python 沒多大用,并且 parser.c 的代碼行數(shù)多達(dá) 4w 多行,讀起來也很痛苦。