[Python源码学习] 之 Python解释器
来源:互联网 发布:php权限修饰符 编辑:程序博客网 时间:2024/06/06 00:23
源码结构
下载Python的源码,解压,即可看到源码的目录结构。
- 奇怪:Python2.7.2根目录下的 README 文件中有 各个目录的说明,在 Python3.2.1根目录下的README文件中却没有相应的介绍了。
Include/
公有 头文件
Lib/
Python编写的模块
Modules/
C实现的模块
Objects/
内置对象类型的实现
PC/
Windows下构建Python的工程文件
PCbuild/
Parser/
解释器的 parser、tokenizer、input handling
Python/
解释器的 byte-compiler、interpreter
configure
shell 脚本
...
编译
在Windows下: PCbuild 下是VS2008 的工程文件
在linux下:
./configuremakesudo make install
Python解释器
Python 解释器(可执行程序) 本身的代码非常简单,就是调用了 Py_Main 这个函数!
Python2.7
Python3.2
int Py_Main(int argc, char **argv)
int Py_Main(int argc, wchar_t **argv)
PyMain PyRun_AnyFileExFlags PyRun_InteractiveLoopFlags PyRun_InteractiveOneFlags PyParser_ParseFileFlagsEx PyAST_Compile PyEval_EvalCode PyRun_SimpleFileExFlags PyParser_ASTFromFile PyAST_Compile PyEval_EvalCode
调用主要有两个分支
- 交互式
- 执行脚本
二者最终都是
- Parser
- Compile
- Eval
三个步骤。
源码
在python2中,使用的窄字符串,在python3中,使用宽字符串。所以python3的源码乍看起来复杂了好多。
源码:Modules/python.c
- python 2.7
#include "Python.h"intmain(int argc, char **argv){... return Py_Main(argc, argv);}
- python 3.2
#include "Python.h"#include <locale.h>#ifdef MS_WINDOWSintwmain(int argc, wchar_t **argv){ return Py_Main(argc, argv);}#elseintmain(int argc, char **argv){ wchar_t **argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*argc); /* We need a second copies, as Python might modify the first one. */ wchar_t **argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*argc);... res = Py_Main(argc, argv_copy);... return res;}#endif
在 Windows 下,由于链接子系统和入口函数问题,所以有一个单独的 pythonw.exe :源码 PC/WinMain.c
#include "Python.h"#define WIN32_LEAN_AND_MEAN#include <windows.h>int WINAPI wWinMain( HINSTANCE hInstance, /* handle to current instance */ HINSTANCE hPrevInstance, /* handle to previous instance */ LPWSTR lpCmdLine, /* pointer to command line */ int nCmdShow /* show state of window */){ return Py_Main(__argc, __wargv);}
Python2中与此几乎完全相同,用 __argv 取代 __wargv
Py_Main
源码定义在 Modules/main.c
intPy_Main(int argc, wchar_t **argv){... Py_Initialize();... if (command) { sts = run_command(command, &cf); free(command); } else if (module) { sts = RunModule(module, 1); } else {... sts = -1; /* keep track of whether we've already run __main__ */ if (filename != NULL) { sts = RunMainFromImporter(filename); }... if (sts == -1) sts = run_file(fp, filename, &cf); }... if (Py_InspectFlag && stdin_is_interactive && (filename != NULL || command != NULL || module != NULL)) { Py_InspectFlag = 0; /* XXX */ sts = PyRun_AnyFileFlags(stdin, "<stdin>", &cf) != 0; }... Py_Finalize();...}
- 首先处理命令行参数
调用Py_Initialize();
- 执行
-c 指定的命令,run_command 中 调用 PyRun_SimpleStringFlags(...)
-m 指定的模块,RunModule 调用 PyObject_Call(...)
文件名非空,则将文件作为 __main__ 模块导入
run_file 调用 PyRun_AnyFileExFlags(...)
PyRun_AnyFileFlags 调用的也是 PyRun_AnyFileExFlags(...)
调用Py_Finalize();
PyRun_AnyFileExFlags
源码:Python/pythonrun.c
/* Parse input from a file and execute it */intPyRun_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);}
两个分支:
- 交互式
- 脚本文件
下面3个马甲都是直接调用的该函数:
PyRun_AnyFile(FILE *fp, const char *name)PyRun_AnyFileEx(FILE *fp, const char *name, int closeit)PyRun_AnyFileFlags(FILE *fp, const char *name, PyCompilerFlags *flags)
run_mod
前面分流的两个分支,最后又都会调用 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((PyObject*)co, globals, locals); Py_DECREF(co); return v;}
python -c
简单看看 python -c "print('hello')" 这种命令行语句会发生什么?
首先从 Py_Main 看起,
Py_Main
- 解析命令行参数,发现 -c 选项,将命令行中后续内容作为 command 的内容。
- 设置 sys.argv[0] 为 -c
- 通过 run_command() 执行命令
intPy_Main(int argc, wchar_t **argv){... wchar_t *command = NULL;... while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) { if (c == 'c') { size_t len; len = wcslen(_PyOS_optarg) + 1 + 1; command = (wchar_t *)malloc(sizeof(wchar_t) * len); wcscpy(command, _PyOS_optarg); command[len - 2] = '\n'; command[len - 1] = 0; break; }... }... if (command != NULL) { /* Backup _PyOS_optind and force sys.argv[0] = '-c' */ _PyOS_optind--; argv[_PyOS_optind] = L"-c"; }... if (command) { sts = run_command(command, &cf); free(command); }...}
run_command
宽字符串command ==> 转换成unicode对象 ==> 转换成 bytes 对象 ==> 窄字符串
窄字符串传递到 PyRun_SimpleStringFalgs
static intrun_command(wchar_t *command, PyCompilerFlags *cf){ PyObject *unicode, *bytes; int ret; unicode = PyUnicode_FromWideChar(command, -1); bytes = PyUnicode_AsUTF8String(unicode); Py_DECREF(unicode); ret = PyRun_SimpleStringFlags(PyBytes_AsString(bytes), cf); Py_DECREF(bytes); return ret != 0;}
这儿调用的PyRun_SimpleStringFlags 将会调用 PyRun_StringFlags 进而将调用 run_mod,这又回到了前面所看到的代码。
参考
http://docs.python.org/py3k/c-api/veryhigh.html
- Python源码剖析,陈儒
- [Python源码学习] 之 Python解释器
- [Python源码学习] 之 Python解释器 http://blog.csdn.net/dbzhang800/article/details/6683440
- python学习之指定脚本解释器
- python学习——python解释器
- [Python学习]解释器Interpreter
- Python编程之解释器
- [Python源码学习]之数据类型
- [Python源码学习]之bytecode
- [Python源码学习]之Py_InitializeEx
- Python源码学习七 .py文件的解释
- Python学习(1)-解释器
- python设计模式之解释器模式
- 【Python】学习笔记——-4、Python解释器
- Python 学习成长记(二)---- Python解释器简介
- Python基础之windows安装python交互解释器
- 廖雪峰python教程阅读之python解释器
- [Python源码学习]之PyObject和PyTypeObject
- [Python源码学习]之整数类型PyIntObject
- container_of 理解
- 企业文件服务器搭建案例
- bochs使用(linux下搭建操作系统开发环境,转)
- JSP中page指令isThreadSafe
- container_of 理解
- [Python源码学习] 之 Python解释器
- java面试笔试题大汇总
- Windows下程序自删除资料收集
- 嵌入式Linux之我行——S3C2440上LCD驱动(FrameBuffer)实例开发讲解(一)
- Linux学习中遇到过的问题
- modelsim is exiting with code:211 10秒后自动关闭退出
- 2011-8-13 0:35:15
- poll机制分析[转载]
- 单片机的C语言中位操作用法