设为首页 收藏本站
查看: 1153|回复: 0

[经验分享] [Python源码学习] 之 Python解释器

[复制链接]

尚未签到

发表于 2017-4-21 11:59:37 | 显示全部楼层 |阅读模式

源码结构



下载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 <locale.h>

#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 <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

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


参考






  • http://docs.python.org/py3k/c-api/veryhigh.html

  • Python源码剖析,陈儒

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-367387-1-1.html 上篇帖子: 【Python旧时笔记 一】Python对象基础 下篇帖子: [Python] 安装及环境配置
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表