博客:blog.shinelee.me | 博客園 | CSDNpython
若是對Python源碼感興趣,那「窺探」其實現的最佳方式就是調教它,不,調試它。git
Python的官方默認實現爲CPython,即C語言實現(主要指解釋器的實現,其餘實現見Other Interpreter Implementations)。CPython的源代碼能夠從官網pyhton.org或者github.com/python/cpython獲取,目前最新的穩定版本爲3.8.0,於2019.10.14發佈。這裏,從官網 https://www.python.org/downloads/release/python-380/ 下載源碼壓縮包,以下圖所示,github
解壓後,目錄結構以下windows
{ Python-3.8.0 } » tree -d -L 1 . . ├── Doc # rst(reStructuredText)格式官方文檔,用其生成https://docs.python.org/ ├── Grammar # Python的EBNF(Extended Backus–Naur form)語法定義文件 ├── Include # .h 頭文件 ├── Lib # .py 純Python實現的標準庫 ├── m4 # ? ├── Mac # Mac-specific code,支持MacOS ├── Misc # Things that do not belong elsewhere. ├── Modules # C實現的標準庫,內含.c .asm .macros .h ├── Objects # 內置數據類型實現 ├── Parser # Python語法分析器源碼 ├── PC # Windows-specific code,支持Windows ├── PCbuild # Windows生成文件,for MSVC ├── Programs # main函數文件,用於生成可執行文件,如python.exe的入口文件 ├── Python # CPython解釋器源碼 └── Tools # 獨立工具代碼,used to maintain Python
CPython的源碼組織結構以下,摘抄自CPython Source Code Layout,bash
源碼文件分門別類存放,並且,不管是py實現的標準庫、c實現的標準庫、內置數據類型仍是內置函數,在Lib/test/
和Doc/library/
目錄下都有與之對應的test_x.py測試文件和rst文檔文件(對於內置數據類型和函數,其文檔集中保存在stdtypes.rst和functions.rst)。好比,內置類型int
位於Objects/longobject.c
文件中。ide
下面正式開始編譯CPython。函數
據Compile and build on Windows,Python3.6及以後的版本可使用VS2017編譯,安裝VS2017時,記得勾選 Python development 和 Python native development tools,有備無患。工具
安裝好VS2017後,雙擊PCbuild/pcbuild.sln
,打開解決方案。由於咱們的關注點僅在Python內核和解釋器部分,因此僅編譯python和pythoncore,其餘模塊暫時忽略,具體地,測試
此時再「生成解決方案」,生成目錄爲PCbuild/win32
,內容以下,含解釋器python_d.exe和內核python38_d.dll,
接下來,將項目python設爲啓動項目(默認狀態便是啓動項目),點擊調試,運行獲得以下控制檯,能夠像平時使用python同樣,與之交互。
若是想生成所有模塊,須要運行PCbuild\get_externals.bat
下載依賴,再編譯,具體可參見Build CPython on Windows。
只要程序能運行起來,一切就好辦了。憑藉「宇宙最強IDE」,咱們能夠任性地設斷點調試甚至修改代碼。
F5
從新啓動調試,彈出控制檯。在上面咱們知道int
類型位於Objects/longobject.c
文件,打開文件,簡單瀏覽後在函數PyObject * PyLong_FromLong(long ival)
入口處打個斷點。而後,在彈出的控制檯中輸入a = 1
來建立int
對象,回車,程序停在了斷點處,查看變量ival
的值爲1——恰爲咱們輸入的數值,這個函數會跟根據輸入的C long int建立一個int
對象,返回對象指針。
再來看看函數調用堆棧,以下圖所示,
調用順序從下至上,從中能夠推斷出,
int
對象繼續運行,彈出的控制檯中光標前出現<<<
,等待輸入。這時若是咱們點擊調試中的中止按鈕(所有中斷),會發現程序停在Parser/myreadline.c
文件_PyOS_WindowsConsoleReadline
函數中的ReadConsoleW
一行,
if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) { err = GetLastError(); goto exit; }
ReadConsoleW
爲WINAPI,詳見ReadConsole function,其等待並讀取控制檯的輸入,讀取的字符保存在wbuf
中。若是有輸入,則進入上面的流程,解析→創建語法樹→……
至此,咱們揭開了Python面紗的一角——不過是一個可運行、可調試的程序而已(微笑)。