Python源码分析
本文环境python2.5系列
参考书籍<<Python源码剖析>>
Python简介:
python主要是动态语言,虽然Python语言也有编译,生成中间字节码,但是它还是一种动态语言,边解释边运行。让我们去揭开Python的一些基础分析。
分析
首先,可以上官网获取Python2.5的源代码,下载源代码后可以打开代码的目录,其中主要有目录
Include: 所有的头文件;
Python: Python核心的解释器执行,线程等主要功能;
Lib:由Python语言编写的包;
Modules: 用C语言编写的模块,当中还包括入口函数;
Parser: Python语言的词法分析与语法分析模块,该流程与编译原理的基础知识一样;
Objects: Python语言的内建对象。
以上为基础信息介绍,接下来就简析一下Python的启动与入口函数。
位于Modules/python.c中
#include "Python.h"
#ifdef __FreeBSD__
#include <floatingpoint.h>
#endif
int
main(int argc, char **argv)
{
/* 754 requires that FP exceptions run in "no stop" mode by default,
* and until C vendors implement C99's ways to control FP exceptions,
* Python requires non-stop mode. Alas, some platforms enable FP
* exceptions by default. Here we disable them.
*/
#ifdef __FreeBSD__
fp_except_t m;
m = fpgetmask();
fpsetmask(m & ~FP_X_OFL);
#endif
return Py_Main(argc, argv);
}
当在命令行中调用 python时,直接就进入了Py_Main函数,
int
Py_Main(int argc, char **argv)
{
...
Py_Initialize(); # 进行初始化操作
...
if (command) {
sts = PyRun_SimpleStringFlags(command, &cf) != 0;
free(command);
} else if (module) {
sts = RunModule(module);
free(module);
}
else {
if (filename == NULL && stdin_is_interactive) {
RunStartupFile(&cf);
}
/* XXX */
sts = PyRun_AnyFileExFlags(
fp,
filename == NULL ? "<stdin>" : filename,
filename != NULL, &cf) != 0; # 进入命令行或者输入文件的交换模式
}
...
}
这里省略部分其他如帮助信息等输入参数的分析,由此可以看到,Python首先会进行初始化Py_Initialize,然后在调用PyRun_AnyFileExFlags进行处理,首先先看想Py_Initialize做了哪些工作;
void
Py_InitializeEx(int install_sigs)
{
PyInterpreterState *interp; // 解释器对象
PyThreadState *tstate; // 线程对象
PyObject *bimod, *sysmod;
char *p;
#if defined(Py_USING_UNICODE) && defined(HAVE_LANGINFO_H) && defined(CODESET)
char *codeset;
char *saved_locale;
PyObject *sys_stream, *sys_isatty;
#endif
extern void _Py_ReadyTypes(void);
if (initialized)
return;
initialized = 1; // 是否已经初始化标志位
if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0') // 设置标志位
Py_DebugFlag = add_flag(Py_DebugFlag, p);
if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '\0')
Py_VerboseFlag = add_flag(Py_VerboseFlag, p);
if ((p = Py_GETENV("PYTHONOPTIMIZE")) && *p != '\0')
Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p);
interp = PyInterpreterState_New(); // 获取一个新的解析器对象
if (interp == NULL)
Py_FatalError("Py_Initialize: can't make first interpreter");
tstate = PyThreadState_New(interp); // 生成第一个线程
if (tstate == NULL)
Py_FatalError("Py_Initialize: can't make first thread");
(void) PyThreadState_Swap(tstate); // 将生成的线程对象设置成当前要运行的线程对象
_Py_ReadyTypes(); // 检查对象type是否能创建等检查操作
if (!_PyFrame_Init()) // 检查当前运行的栈帧
Py_FatalError("Py_Initialize: can't init frames");
if (!_PyInt_Init())
Py_FatalError("Py_Initialize: can't init ints"); // 创建小整数缓存池
_PyFloat_Init(); // 检查当前运行计算机的float方式
interp->modules = PyDict_New(); // 新建一个字典对象作为当前解释器对象的modules, __builtin__中的方法就会放入其中
if (interp->modules == NULL)
Py_FatalError("Py_Initialize: can't make modules dictionary");
#ifdef Py_USING_UNICODE
/* Init Unicode implementation; relies on the codec registry */
_PyUnicode_Init();
#endif
bimod = _PyBuiltin_Init(); // 将内建对象等方法加入到interp->modules字典中
if (bimod == NULL)
Py_FatalError("Py_Initialize: can't initialize __builtin__");
interp->builtins = PyModule_GetDict(bimod); // 将内建对象方法等,放入解释器的builtins中
if (interp->builtins == NULL)
Py_FatalError("Py_Initialize: can't initialize builtins dict");
Py_INCREF(interp->builtins);
sysmod = _PySys_Init(); // sys模块方法的初始化
if (sysmod == NULL)
Py_FatalError("Py_Initialize: can't initialize sys");
interp->sysdict = PyModule_GetDict(sysmod);
if (interp->sysdict == NULL)
Py_FatalError("Py_Initialize: can't initialize sys dict");
Py_INCREF(interp->sysdict);
_PyImport_FixupExtension("sys", "sys");
PySys_SetPath(Py_GetPath());
PyDict_SetItemString(interp->sysdict, "modules",
interp->modules);
_PyImport_Init();
/* initialize builtin exceptions */
_PyExc_Init(); // 初始化错误的內建方法
_PyImport_FixupExtension("exceptions", "exceptions");
/* phase 2 of builtins */
_PyImport_FixupExtension("__builtin__", "__builtin__");
_PyImportHooks_Init();
if (install_sigs)
initsigs(); /* Signal handling stuff, including initintr() */
initmain(); /* Module __main__ */
if (!Py_NoSiteFlag)
initsite(); /* Module site */
/* auto-thread-state API, if available */
#ifdef WITH_THREAD
_PyGILState_Init(interp, tstate);
#endif /* WITH_THREAD */
warnings_module = PyImport_ImportModule("warnings");
if (!warnings_module)
PyErr_Clear();
#if defined(Py_USING_UNICODE) && defined(HAVE_LANGINFO_H) && defined(CODESET)
/* On Unix, set the file system encoding according to the
user's preference, if the CODESET names a well-known
Python codec, and Py_FileSystemDefaultEncoding isn't
initialized by other means. Also set the encoding of
stdin and stdout if these are terminals. */
...
}
初始化的内容,基本上涵盖了Python运行时的信息,由于Python的执行需要有解释器类型,也需要线程状态类型,构建运行时的内建类型,检查type是否能够正常生成, 检查Python支持的对象能否正常新建等信息。后续有机会会剖析其中部分内容。
接下来就是PyRun_AnyFileExFlags处理
int
PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit,
PyCompilerFlags *flags)
{
if (filename == NULL)
filename = "???";
if (Py_FdIsInteractive(fp, filename)) {
int err = PyRun_InteractiveLoopFlags(fp, filename, flags); // 进入解释器交互模式
if (closeit)
fclose(fp);
return err;
}
else
return PyRun_SimpleFileExFlags(fp, filename, closeit, flags); // 进入执行文本文件模式
}
再次我们查看执行文本模式
int
PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
PyCompilerFlags *flags)
{
PyObject *m, *d, *v;
const char *ext;
m = PyImport_AddModule("__main__"); // 导入__main__
if (m == NULL)
return -1;
d = PyModule_GetDict(m); // 获取导入的__main__内容
if (PyDict_GetItemString(d, "__file__") == NULL) { // 设置当前执行文件的__file__属性值
PyObject *f = PyString_FromString(filename);
if (f == NULL)
return -1;
if (PyDict_SetItemString(d, "__file__", f) < 0) {
Py_DECREF(f);
return -1;
}
Py_DECREF(f);
}
ext = filename + strlen(filename) - 4;
if (maybe_pyc_file(fp, filename, ext, closeit)) { // 尝试检查是否存在编译好的字节码文件,如果已经存在则先运行字节码文件
/* Try to run a pyc file. First, re-open in binary */
if (closeit)
fclose(fp);
if ((fp = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "python: Can't reopen .pyc file\n");
return -1;
}
/* Turn on optimization if a .pyo file is given */
if (strcmp(ext, ".pyo") == 0)
Py_OptimizeFlag = 1;
v = run_pyc_file(fp, filename, d, d, flags);
} else {
v = PyRun_FileExFlags(fp, filename, Py_file_input, d, d,
closeit, flags); // 运行源文件
}
if (v == NULL) {
PyErr_Print();
return -1;
}
Py_DECREF(v);
if (Py_FlushLine())
PyErr_Clear();
return 0;
}
我们继续查看PyRun_FileExFlags
PyObject *
PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals,
PyObject *locals, int closeit, PyCompilerFlags *flags)
{
PyObject *ret;
mod_ty mod;
PyArena *arena = PyArena_New(); // 初始化Python运行时的内存
if (arena == NULL)
return NULL;
mod = PyParser_ASTFromFile(fp, filename, start, 0, 0,
flags, NULL, arena); // 解析Python源文件到字节码内容
if (mod == NULL) {
PyArena_Free(arena);
return NULL;
}
if (closeit)
fclose(fp);
ret = run_mod(mod, filename, globals, locals, flags, arena); // 执行解释后的字节码
PyArena_Free(arena); // 释放Python申请的内存
return ret;
}
此时,我们继续查看run_mod
static PyObject *
run_mod(mod_ty mod, const char *filename, PyObject *globals, PyObject *locals,
PyCompilerFlags *flags, PyArena *arena)
{
PyCodeObject *co;
PyObject *v;
co = PyAST_Compile(mod, filename, flags, arena); // 解析生成自己码
if (co == NULL)
return NULL;
v = PyEval_EvalCode(co, globals, locals); // 执行解析完成后的字节码
Py_DECREF(co);
return v;
}
我们进入PyEval_EvalCode查看字节码的执行
PyObject *
PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
{
/* XXX raise SystemError if globals is NULL */
return PyEval_EvalCodeEx(co,
globals, locals,
(PyObject **)NULL, 0,
(PyObject **)NULL, 0,
(PyObject **)NULL, 0,
NULL);
}
继续查看PyEval_EvalCodeEx
PyObject *
PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
PyObject **args, int argcount, PyObject **kws, int kwcount,
PyObject **defs, int defcount, PyObject *closure)
{
... // 输入参数等处理
retval = PyEval_EvalFrameEx(f,0);
}
此时就进入PyEval_EvalFrameEx,该函数就是Python虚拟机执行的核心函数,该函数会在以后的分析中进行分析。
至此,Python的运行启动到结束的大致流程已经在代码中进行了大概的梳理。