博客: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面纱的一角——不过是一个可运行、可调试的程序而已(微笑)。