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>
#endifint
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);
#endifreturn 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;
#endifextern 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();
#endifbimod = _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 theuser's preference, if the CODESET names a well-knownPython codec, and Py_FileSystemDefaultEncoding isn'tinitialized by other means. Also set the encoding ofstdin 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;}elsereturn 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的运行启动到结束的大致流程已经在代码中进行了大概的梳理。

Python源码学习:启动流程简析相关推荐

  1. Android开机启动流程简析

    Android开机启动流程简析 (一) 文章目录 Android开机启动流程简析 (一) 前言 一.开机启动的流程概述 二.Android的启动过程分析 (1).总体流程 init简述 Zygote简 ...

  2. 渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(上)

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/11/es-code02/ 前提 上篇文章写了 ElasticSearch 源码解析 -- ...

  3. Linux的启动流程简析(以Debian为例)

    Linux的启动流程简析(以Debian为例) 正文: 前面的文章探讨BIOS和主引导记录的作用.那篇文章不涉及操作系统,只与主板的板载程序有关.今天,我想接着往下写,探讨操作系统接管硬件以后发生的事 ...

  4. Python源码学习:内建类型简析并简析int对象

    Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 上一篇文章中已经大致分析了下,Python的启动执行流程,现在我们分析一下Pytho ...

  5. Python源码学习:Python类机制分析-用户自定义类

    Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 上一文,分析了Python在启动初始化时,对内置类的一个基本的初始化流程,本文就简析 ...

  6. Python源码学习:多线程实现机制

    Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 本文分析Python中的多线程机制,主要通过一个多线程的脚本来分析多线程的基本操作与 ...

  7. Python源码学习:Python类机制分析

    Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 本文主要分析Python中类时如何实现的,在Python中,一切都是对象:任何对象都 ...

  8. Python源码学习笔记:Python程序执行过程与字节码

    Python程序执行过程与字节码 注:本篇是根据教程学习记录的笔记,部分内容与教程是相同的,因为转载需要填链接,但是没有,所以填的原创,如果侵权会直接删除. 问题: 我们每天都要编写一些Python程 ...

  9. Python源码学习:Python函数浅析-有参函数

    Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 继续上一篇无参函数的调用后,本文将分析Python中的有参函数的大致流程,在Pyth ...

最新文章

  1. 循环输入正整数,求其平均值
  2. FreeModbus 移植于STM32 实现Modbus RTU通信
  3. UITableView性能提升和优化(第3章) 之一
  4. JVM:查看java内存情况命令
  5. 【嵌入式开发】C语言 指针数组 多维数组
  6. 数据中心机房消防演练方案
  7. verilog经验谈
  8. asp.net中RegularExpressionValidator控件中正则表达式用法
  9. linux 生成hash值命令,linux-从给定哈希计算base64编码哈希?
  10. js百度地图小车html,H5页面引用百度地图绘制车辆历史轨迹
  11. 网页模板素材|解救不会编程的UI设计师网页设计者!
  12. C 和 CPP 混合代码cmath编译出错
  13. Android Button 实现透明 + 圆角按钮效果
  14. 十一月份英语学习总结—积累
  15. 用ABAP编程破解世界上最难数独游戏
  16. java画乌龟_简单的实现java多线程——龟兔赛跑
  17. 人工智能相关书籍介绍
  18. html5开发制作,漂亮html5模板欣赏,H5网站建设
  19. JVM系列:JIT技术概述
  20. 易拉宝Roll up Banner

热门文章

  1. 人工干预如何提高模型性能?看这文就够了!
  2. 一流科技完成5000万人民币A轮融资,高瓴创投独家领投
  3. NLP任务中的文本预处理步骤、工具和示例
  4. 深度学习基础总结,无一句废话(附完整思维导图)
  5. 工作5年后才明白的道理:不起眼的技能中,藏着你的未来
  6. 图灵奖得主Bengio再次警示:可解释因果关系是深度学习发展的当务之急
  7. 中文预训练ALBERT模型来了:小模型登顶GLUE,Base版模型小10倍、速度快1倍
  8. 商汤科技举办病理、放疗两大MICCAI国际挑战赛,推动AI医疗落地
  9. 学习这么多算法到底在解决哪些问题?深度学习之外,我们要选择谁?
  10. 互联网巨头终极战场:得开发者得天下