这一章主要介绍解释器如何执行一个Python程序。
当一个模块被当做参数传给Python的时候,例如python test.py,下面是发生的主要活动。
1. 初始化:main->Py_Main
2. 编译: 解析树生成->抽象语法树生成->字节码生成->字节码优化->代码对象生成
3. 解释:代码对象执行
Python可执行文件其实就是一个C程序,就像在Linux系统上可执行的其他程序一样,例如常见的helloworld程序。
C的运行时执行下面的操作:加载库,检查和设置环境变量,然后像其他C程序一样执行Python可执行文件的main方法。Python可执行文件的main程序在./Programs/python.c文件里,它主要负责一些初始化,例如复制命令行参数给模块,然后main函数调用./Programs/python.c文件里的Py_Main函数,该函数处理解析器的初始化过程-解析命令行参数,设置程序的flag,读取环境变量,运行钩子,完成hash随机化等等。作为初始化的一部分,pylifecycle.c里的Py_Initialize会被调用,它将处理解释器状态和线程状态的数据结构的初始化,这两种数据结构非常重要。
Python解释器的数据结构PyInterpreterState定义如下,主要是一些只想实际存储数据字段的指针。
1 typedef struct _is {
2
3 struct _is *next;
4 struct _ts *tstate_head;
5
7 PyObject *modules_by_index;
8 PyObject *sysdict;
9 PyObject *builtins;
10 PyObject *importlib;
11
12 PyObject *codec_search_path;
13 PyObject *codec_search_cache;
14 PyObject *codec_error_registry;
15 int codecs_initialized;
16 int fscodec_initialized;
17
18 PyObject *builtins_copy;
19 } PyInterpreterState;
1. *next只想其他的解释器实例,所以一个进程中可以有多个python解释器。
2. *tstate_head 指向主线程
3. modules, modules_by_index, sysdict, builtins and importlib这些呢都是自解释的,他们都是PyObject的实例,PyObject是Python虚拟机世界里所有对象的根类型。
4. *codec相关的字段帮助定位和加载编码,对解码相当有用。
程序的执行必须在线程中进行,线程的状态结构包含了一个线程执行python代码对象所需的所有信息,下面是线程数据结构的一部分
1 typedef struct _ts {
2 struct _ts *prev;
3 struct _ts *next;
4 PyInterpreterState *interp;
5
6 struct _frame *frame;
7 int recursion_depth;
8 char overflowed;
9
10 char recursion_critical;
11 int tracing;
12 int use_tracing;
13
14 Py_tracefunc c_profilefunc;
15 Py_tracefunc c_tracefunc;
16 PyObject *c_profileobj;
17 PyObject *c_traceobj;
18
19 PyObject *curexc_type;
20 PyObject *curexc_value;
21 PyObject *curexc_traceback;
22
23 PyObject *exc_type;
24 PyObject *exc_value;
25 PyObject *exc_traceback;
26
27 PyObject *dict; /* Stores per-thread state */
28 int gilstate_counter;
29
30 …
24 PyObject *exc_value;
31 } PyThreadState;