python解释器源码 pdf_[Python源码学习] 之 Python解释器

源码结构

下载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下:

./configure

make

sudo 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"

int

main(int argc, char **argv)

{

...

return Py_Main(argc, argv);

}

python 3.2

#include "Python.h"

#include

#ifdef MS_WINDOWS

int

wmain(int argc, wchar_t **argv)

{

return Py_Main(argc, argv);

}

#else

int

main(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

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

int

Py_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, "", &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 */

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);

}

两个分支:

交互式

脚本文件

下面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() 执行命令

int

Py_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 int

run_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,这又回到了前面所看到的代码。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值