『Python底层原理』--CPython如何运行Python代码
Python作为一种广泛使用的编程语言,其简洁的语法和强大的功能深受开发者喜爱。
然而,对于许多Python用户来说,CPython(Python的官方实现)的内部工作机制仍然是一个神秘的黑盒。
今天,我们将继续探索CPython的源代码,尝试了解Python从程序启动到字运行的神秘面纱。
1. CPython代码概要
CPython的代码库规模庞大,包含约35万行C代码和近60万行Python代码。
这些代码分布在多个目录中,这些目录结构为CPython的开发和维护提供了清晰的组织方式。
主要的目录包括:
Grammar/:Python语法文件Include/:头文件Lib/:标准库模块(Python实现)Modules/:标准库模块(C实现)Objects/:内置类型实现。Parser/:解析器相关代码Programs/:可执行文件的源码Python/:解释器核心代码
CPython是开源的,代码托管在gihtub上,感兴趣的话,可以下载了查看。
下载了之后,可以切换到自己感兴趣的分支版本。
git clone https://github.com/python/cpython/ && cd cpython
git checkout 3.12
编译源码过程相对简单,只需运行以下命令即可:
./configure
make
make test
sudo make install
编译完成后,运行 ./python.exe 即可启动自己编译的CPython版本。
2. 启动Python
CPython的入口点是 main() 函数,位于 Programs/python.c 文件中。
/* Minimal main program -- everything is loaded from the library */
#include "Python.h"
#ifdef MS_WINDOWS
int
wmain(int argc, wchar_t **argv)
{
return Py_Main(argc, argv);
}
#else
int
main(int argc, char **argv)
{
return Py_BytesMain(argc, argv);
}
#endif
这个函数是程序启动的起点,负责初始化CPython并开始执行用户代码。
在Windows平台上,CPython使用 wmain() 作为入口点,以支持UTF-16编码的命令行参数。这种设计使得CPython能够更好地处理不同平台上的字符编码问题。
main()函数的主要职责是调用Py_Main()或Py_BytesMain(),这两个函数分别处理宽字符和字节字符串的命令行参数。
Py_Main和Py_BytesMain位于 Modules/main.c 文件中。
这两个函数进一步调用pymain_main(),开始CPython的初始化过程。
Py_Main,Py_BytesMain以及pymain_main这些函数都在Modules/main.c 文件中。
3. 初始化Python
CPython的初始化过程分为三个阶段:预初始化、核心初始化和主初始化,每个阶段都有其特定的任务和目标。
- 预初始化:
预初始化阶段主要负责设置运行时状态、默认内存分配器和基本配置。
这一阶段通过调用 _PyRuntime_Initialize() 和 PyPreConfig_InitPythonConfig() 等函数来完成。
这些函数初始化了CPython的全局运行时状态,并为后续的初始化阶段做好了准备。
其中,_PyRuntime_Initialize函数的实现位于:Python/pylifecycle.c
PyPreConfig_InitPythonConfig函数的实现位于:Python/preconfig.c
- 核心初始化:
核心初始化阶段是CPython初始化的关键部分。
这一阶段初始化了主解释器状态、线程状态、内置类型、 builtins 模块、 sys 模块和导入系统。
这些组件构成了Python运行的核心基础,使得CPython能够开始执行Python代码。
核心初始化通过调用 Py_InitializeFromConfig() 函数来完成,该函数进一步调用了 pyinit_core() 等函数,逐步构建了Python运行时的核心环境。
其中,Py_InitializeFromConfig函数的实现位于:Python/pylifecycle.c
- 主初始化:
主初始化阶段是CPython初始化的最后一步。
这一阶段完成了CPython的全面初始化,包括设置 sys.path 、导入 site 模块等。
这些任务使得CPython能够支持完整的Python功能,包括模块导入和脚本执行。
主初始化通过调用 pyinit_main() 函数来完成,该函数进一步调用了 init_interp_main() 等函数,完成了CPython的最终配置。
其中,pyinit_main和init_interp_main函数的实现位于:Python/pylifecycle.c
4. 运行Python
初始化完成后,CPython进入程序运行阶段。Py_RunMain() 函数(Modules/main.c文件中)是这一阶段的核心,它负责运行Python程序并进行清理。
根据不同的运行模式(如脚本、模块、命令行等), Py_RunMain() 函数调用不同的函数来执行代码。
例如, pymain_run_python() 函数处理 sys.path 的设置和模块的导入,确保Python程序能够在正确的环境中运行。
5. 编译和执行
Python代码的编译和执行是CPython运行的核心部分。
PyRun_FileExFlags()函数(Python/pythonrun.c文件中)是这一过程的入口点,它负责将Python代码编译为字节码,并将其加载到运行时环境中。
编译过程通过调用 _PyAST_Compile() 函数(Python/compile.c文件中)完成,该函数将抽象语法树(AST)编译为代码对象。
最终,PyEval_EvalCode() 函数(Python/pythonrun.c文件中)执行代码对象,进入字节码执行循环。
字节码执行循环是CPython运行的最后阶段。
这一阶段通过调用 _PyEval_EvalFrame() 函数(Include/internal/pycore_ceval.h文件中)来执行字节码指令,_PyEval_EvalFrame() 函数是一个复杂的函数,它负责处理各种Python操作,包括函数调用、变量访问和异常处理等。
如果想更好地理解Python的运行机制,可以深入研究这个函数。
6. 总结
本文主要从CPython源代码的角度来了解Python程序从启动到执行的全过程。
源代码是基于CPyhton 3.12 分支的。
通过阅读和分析CPython的源代码,我们不仅能够更好地理解Python的内部机制,还能够发现优化和改进的机会。
如果对CPython的内部工作机制感兴趣,最好能够亲自探索其源代码。通过阅读和理解源代码,将获得更深入的知识,并能够更好地利用Python的强大功能。
『Python底层原理』--CPython如何运行Python代码的更多相关文章
- 前端与编译原理 用js去运行js代码 js2run
# 前端与编译原理 用js去运行js代码 js2run 前端与编译原理似乎相隔甚远,各种热门的框架都学不过来,那能顾及到这么多底层呢,前端开发者们似乎对编译原理的影响仅仅是"抽象语法树&qu ...
- 编程语言、Python介绍及其解释器安装、运行Python解释器的两种方式、变量、内存管理
一.编程语言介绍 1.1 机器语言:直接用计算机能理解的二进制指令来编写程序,直接控制硬件. 1.2 汇编语言:在机器语言的基础上,用英文标签取代二进制指令来编写程序,本质上也是直接控制硬件. 以上2 ...
- python 使用Nginx和uWSGI来运行Python应用
参考:http://zmrenwu.com/post/20/ uWSGI是一个Web应用服务器,它具有应用服务器,代理,进程管理及应用监控等功能.它支持WSGI协议,同时它也支持自有的uWSGI协议, ...
- python底层原理
有同学问到了一个问题,python中存储变量是通过内存地址来存储,那么python又是如何去判断内存中的地址是什么数据类型的呢.经过查找,找到这篇文章: 原博客地址:http://www.cnblog ...
- Python 底层原理知识
1.Python是如何进行内存管理的? 答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制 一.对象的引用计数机制 Python内部使用引用计数,来保持追踪内存中的对象,所有对象都 ...
- Python:在命令行窗口中运行Python程序
首先通过cd进入程序所在目录下 再通过python或者python3加要运行的python文件即可
- 在 vscode.dev 中直接运行 Python !纯浏览器环境,无后端!
其实有挺长一段时间没有写自己的 VS Code 插件了! 还是要感谢我们 DevDiv 组的 Flexible Friday 活动,让我可以在工作日研究自己感兴趣的项目. Flexible Frida ...
- 在 android 上运行 python 的方法
在android上运行python脚本,或者在android上使用python交互界面,对熟悉python的研究或开发人员来说,是一件很有吸引力的事情,因为python脚本真是非常高效,另外,有很多非 ...
- 『现学现忘』Docker基础 — 16、Docker中的基本概念和底层原理
目录 1.Docker的底层原理 2.Docker中常用的基本概念 3.run命令的运行流程 4.为什么Docker比VM快 Docker架构图: 我们依照Docker架构图进行Docker基础概念的 ...
- python进阶(24)Python字典的底层原理以及字典效率
前言 问题1:python中的字典到底是有序还是无序 问题2:python中字典的效率如何 python字典底层原理 在Python 3.5以前,字典是不能保证顺序的,键值对A先插入字典,键值对B ...
随机推荐
- MySQL8.0安装与使用
Windows: 1.下载:https://dev.mysql.com/downloads/mysql/ 推荐使用镜像:http://mirrors.sohu.com/mysql/MySQL-8.0/ ...
- Node.js 文件读写
1.fs模块 在node.js中,所有文件的操作都是通过fs模块来实现的.包括文件目录的创建,删除,查询以及文件的读取,写入. 在fs模块中,所有的方法都分成同步和异步两种实现,具有sync后缀的为同 ...
- Vue.js与jQuery混用
标签: js 坑位 最近开发一个需求,项目有用到jQuery和Vue,发现我jQuery绑定的事件全部都失效了. Why Vue会重新渲染dom,加上是异步实例Vue.所以正常写程序的话jq的$()获 ...
- QEMU CVE-2021-3947 和 CVE-2021-3929 漏洞利用分析
QEMU CVE-2021-3947 和 CVE-2021-3929 漏洞利用分析 CVE-2021-3947 信息泄露漏洞 漏洞分析 漏洞点是 nvme_changed_nslist stati ...
- 【Amadeus原创】修改docker里面网站的port端口映射
切记:以下顺序千万不能颠倒!否则不生效! 1. 查看需要修改的容器,记住container id docker ps -a 2. 停止容器 docker stop xxx 3. 修改容器的端口映射配置 ...
- less 常用方法
介绍 Less 是 CSS 的预处理语言之一,为 CSS 增添了变量.Mixin.函数等特性,使CSS更易于维护扩展. 嵌套(Nesting) .header { .navgation: { font ...
- 渗透测试-前端加密分析之RSA响应加密
本文是高级前端加解密与验签实战的第7篇文章,本系列文章实验靶场为Yakit里自带的Vulinbox靶场,本文讲述的是绕过请求包和响应包加密来爆破登录界面. 分析 这里的公私钥同上文一样是通过服务端获取 ...
- java int转byte数组
int 转 byte[] 低字节在前(低字节序)public static byte[] toLH(int n) { byte[] b = new byte[4]; b[0] = (byte) (n ...
- .NET Core 类型系统(Types System)底层原理浅谈
C#类型系统 C# 是一种强类型语言. 每个变量和常量都有一个类型,每个求值的表达式也是如此. 每个方法声明都为每个输入参数和返回值指定名称.类型和种类(值.引用或输出). .NET 类库定义了内置数 ...
- Qt/C++如何选择使用哪一种地图内核/不同地图的优缺点/百度高德腾讯地图/天地图/谷歌地图
一.前言说明 最近花了大半年时间,专门研究这个地图组件,几乎把各种地图的官网的手册翻了个遍,亲自写代码验证了一遍,各种API函数接口和功能全部实战一遍,然后从中提取共性,做出了基类,以及通用函数类,子 ...