Python3源码分析

本文环境python3.5.2。
参考书籍<<Python源码剖析>>
python官网

Python3的sys模块初始化

根据分析完成builtins初始化后,继续分析sys模块的初始化,继续分析_Py_InitializeEx_Private函数的执行,

void
_Py_InitializeEx_Private(int install_sigs, int install_importlib)
{...sysmod = _PySys_Init();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_FixupBuiltin(sysmod, "sys");PySys_SetPath(Py_GetPath());PyDict_SetItemString(interp->sysdict, "modules",interp->modules);...
}

此时继续分析,_PySys_Init函数,

PyObject *
_PySys_Init(void)
{PyObject *m, *sysdict, *version_info;int res;m = PyModule_Create(&sysmodule);                                        // 创建模块if (m == NULL)return NULL;sysdict = PyModule_GetDict(m);                                          // 获取模块的属性字典
#define SET_SYS_FROM_STRING_BORROW(key, value)             \do {                                                   \PyObject *v = (value);                             \if (v == NULL)                                     \return NULL;                                   \res = PyDict_SetItemString(sysdict, key, v);       \                // 设置到sysdict字典中if (res < 0) {                                     \return NULL;                                   \}                                                  \} while (0)
#define SET_SYS_FROM_STRING(key, value)                    \do {                                                   \PyObject *v = (value);                             \if (v == NULL)                                     \return NULL;                                   \res = PyDict_SetItemString(sysdict, key, v);       \                // 设置到sysdict字典中Py_DECREF(v);                                      \if (res < 0) {                                     \return NULL;                                   \}                                                  \} while (0).../* stdin/stdout/stderr are set in pylifecycle.c */SET_SYS_FROM_STRING_BORROW("__displayhook__",PyDict_GetItemString(sysdict, "displayhook"));SET_SYS_FROM_STRING_BORROW("__excepthook__",PyDict_GetItemString(sysdict, "excepthook"));SET_SYS_FROM_STRING("version",PyUnicode_FromString(Py_GetVersion()));        // 版本相关信息...     SET_SYS_FROM_STRING("platform",PyUnicode_FromString(Py_GetPlatform()));        // 平台相关信息... /* initialize hash_info */if (Hash_InfoType.tp_name == NULL) {if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < 0)return NULL;}SET_SYS_FROM_STRING("hash_info",get_hash_info());                               // hash相关信息...SET_SYS_FROM_STRING("builtin_module_names",list_builtin_module_names());                   // 内建模块信息
#if PY_BIG_ENDIANSET_SYS_FROM_STRING("byteorder",PyUnicode_FromString("big"));                   // 大端排序
#elseSET_SYS_FROM_STRING("byteorder",PyUnicode_FromString("little"));                // 小断排序
#endif..SET_SYS_FROM_STRING_BORROW("warnoptions", warnoptions);SET_SYS_FROM_STRING_BORROW("_xoptions", get_xoptions());...SET_SYS_FROM_STRING("flags", make_flags());                         // 获取当前运行的flags...#ifdef WITH_THREADSET_SYS_FROM_STRING("thread_info", PyThread_GetInfo());             // 返回线程相关信息
#endif...return m;
}

由该函数可知,初始了相关的函数或属性来描述和提供系统平台相关信息,完成后,

    interp->sysdict = PyModule_GetDict(sysmod);if (interp->sysdict == NULL)Py_FatalError("Py_Initialize: can't initialize sys dict");Py_INCREF(interp->sysdict);_PyImport_FixupBuiltin(sysmod, "sys");PySys_SetPath(Py_GetPath());

继续执行已经分析过的将sysmod设置到extensions中,设置interp的sysdict为初始化完成的字典,调用PySys_SetPath设置搜索路径,接下来分析一下该函数,

wchar_t *
Py_GetPath(void)
{if (!module_search_path)            // 如果module_search_path没有初始化calculate_path();               // 创建搜索路径return module_search_path;
}   void
PySys_SetPath(const wchar_t *path)
{PyObject *v;if ((v = makepathobject(path, DELIM)) == NULL)  // 设置路径Py_FatalError("can't create sys.path");if (_PySys_SetObjectId(&PyId_path, v) != 0)     // 设置到interp->sysdict字典中Py_FatalError("can't assign sys.path");Py_DECREF(v);
}

对于calculate_path和makepathobject函数可自行分析,这就设置好了模块的搜索路径,此后继续执行,

    PyDict_SetItemString(interp->sysdict, "modules",interp->modules);

将interp的sysdict中添加modules,该modules就是添加的modules,至此sys模块的初始化完成。

Python3的main和site-packages的初始化

此时_Py_InitializeEx_Private执行如下代码,

void
_Py_InitializeEx_Private(int install_sigs, int install_importlib)
{..._PyImport_Init();                               // 初始化导入模块...import_init(interp, sysmod);...if (install_sigs)initsigs(); /* Signal handling stuff, including initintr() */  // 注册相关信号initmain(interp); /* Module __main__ */                            // 设置成__main__...if (!Py_NoSiteFlag)initsite(); /* Module site */                                  // 导入site中的模块
}

调用到_PyImport_Init,

void
_PyImport_Init(void)
{PyInterpreterState *interp = PyThreadState_Get()->interp;       // 获取解释器initstr = PyUnicode_InternFromString("__init__");               // 设置__init__if (initstr == NULL)Py_FatalError("Can't initialize import variables");interp->builtins_copy = PyDict_Copy(interp->builtins);          // 拷贝解释器的builtins到builtins_copyif (interp->builtins_copy == NULL)Py_FatalError("Can't backup builtins dict");
}

主要工作就是将interp的builtins设置到builtins_copy中,此时执行完后,执行到initsigs,

PyOS_sighandler_t
PyOS_setsig(int sig, PyOS_sighandler_t handler)
{
#ifdef HAVE_SIGACTION/* Some code in Modules/signalmodule.c depends on sigaction() being* used here if HAVE_SIGACTION is defined.  Fix that if this code* changes to invalidate that assumption.*/struct sigaction context, ocontext;context.sa_handler = handler;sigemptyset(&context.sa_mask);context.sa_flags = 0;if (sigaction(sig, &context, &ocontext) == -1)return SIG_ERR;return ocontext.sa_handler;
#elsePyOS_sighandler_t oldhandler;oldhandler = signal(sig, handler);          // 设置信号量
#ifdef HAVE_SIGINTERRUPTsiginterrupt(sig, 1);
#endifreturn oldhandler;
#endif
}void
PyOS_InitInterrupts(void)
{PyObject *m = PyImport_ImportModule("_signal");     // 导入_signalif (m) {Py_DECREF(m);}
}...static void
initsigs(void)
{
#ifdef SIGPIPEPyOS_setsig(SIGPIPE, SIG_IGN);
#endif
#ifdef SIGXFZPyOS_setsig(SIGXFZ, SIG_IGN);
#endif
#ifdef SIGXFSZPyOS_setsig(SIGXFSZ, SIG_IGN);
#endifPyOS_InitInterrupts(); /* May imply initsignal() */             // 注册信号量if (PyErr_Occurred()) {Py_FatalError("Py_Initialize: can't import signal");}
}

主要执行的工作就是将相关的信号任务注册,执行完成后,执行initmain(interp)函数,

/* Create __main__ module */static void
initmain(PyInterpreterState *interp)
{PyObject *m, *d, *loader;m = PyImport_AddModule("__main__");                                     // 添加一个__main__ moduleif (m == NULL)Py_FatalError("can't create __main__ module");d = PyModule_GetDict(m);                                                // 获取新建模块的属性字典if (PyDict_GetItemString(d, "__builtins__") == NULL) {                  // 如果获取不到__builtins__值PyObject *bimod = PyImport_ImportModule("builtins");                // 导入builtins,先从全局中查找,找不到则导入if (bimod == NULL) {Py_FatalError("Failed to retrieve builtins module");}if (PyDict_SetItemString(d, "__builtins__", bimod) < 0) {           // 设置到__builtins__ 属性中Py_FatalError("Failed to initialize __main__.__builtins__");}Py_DECREF(bimod);}/* Main is a little special - imp.is_builtin("__main__") will return* False, but BuiltinImporter is still the most appropriate initial* setting for its __loader__ attribute. A more suitable value will* be set if __main__ gets further initialized later in the startup* process.*/loader = PyDict_GetItemString(d, "__loader__");                         // 获取__loader__属性if (loader == NULL || loader == Py_None) {                              // 获取不到PyObject *loader = PyObject_GetAttrString(interp->importlib,"BuiltinImporter");       // 获取importlib的BuiltinImporter属性if (loader == NULL) {Py_FatalError("Failed to retrieve BuiltinImporter");}if (PyDict_SetItemString(d, "__loader__", loader) < 0) {            // 设置该属性Py_FatalError("Failed to initialize __main__.__loader__");}Py_DECREF(loader);}
}

main模块就是作为主程序运行的Python模块,执行完成后,继续执行

    if (!Py_NoSiteFlag)initsite(); /* Module site */

initsite函数就是导入site-packages中存在的Python的模块,

/* Import the site module (not into __main__ though) */static void
initsite(void)
{PyObject *m;m = PyImport_ImportModule("site");                              // 导入site模块if (m == NULL) {fprintf(stderr, "Failed to import the site module\n");PyErr_Print();Py_Finalize();exit(1);}else {Py_DECREF(m);}
}

查看PyImport_ImportModule函数,

PyObject *
PyImport_ImportModule(const char *name)
{PyObject *pname;PyObject *result;pname = PyUnicode_FromString(name);if (pname == NULL)return NULL;result = PyImport_Import(pname);Py_DECREF(pname);return result;
}...
PyObject *
PyImport_Import(PyObject *module_name)
{static PyObject *silly_list = NULL;static PyObject *builtins_str = NULL;static PyObject *import_str = NULL;PyObject *globals = NULL;PyObject *import = NULL;PyObject *builtins = NULL;PyObject *modules = NULL;PyObject *r = NULL;/* Initialize constant string objects */if (silly_list == NULL) {import_str = PyUnicode_InternFromString("__import__");      // __import__属性值if (import_str == NULL)return NULL;builtins_str = PyUnicode_InternFromString("__builtins__");  // __builtins__属性值if (builtins_str == NULL)return NULL;silly_list = PyList_New(0);                                 // 设值listif (silly_list == NULL)return NULL;}/* Get the builtins from current globals */globals = PyEval_GetGlobals();                                  // 获取全局变量if (globals != NULL) {Py_INCREF(globals);builtins = PyObject_GetItem(globals, builtins_str);         // 从全局变量中获取内建类型if (builtins == NULL)goto err;}else {/* No globals -- use standard builtins, and fake globals */builtins = PyImport_ImportModuleLevel("builtins",NULL, NULL, NULL, 0); // 导入builtinsif (builtins == NULL)return NULL;globals = Py_BuildValue("{OO}", builtins_str, builtins);    // 设值if (globals == NULL)goto err;}/* Get the __import__ function from the builtins */if (PyDict_Check(builtins)) {import = PyObject_GetItem(builtins, import_str);if (import == NULL)PyErr_SetObject(PyExc_KeyError, import_str);}elseimport = PyObject_GetAttr(builtins, import_str);if (import == NULL)goto err;/* Call the __import__ function with the proper argument listAlways use absolute import here.Calling for side-effect of import. */r = PyObject_CallFunction(import, "OOOOi", module_name, globals,globals, silly_list, 0, NULL);        // 导入模块if (r == NULL)goto err;Py_DECREF(r);modules = PyImport_GetModuleDict();                             // 获取interp的modulesr = PyDict_GetItem(modules, module_name);                       // 获取module_name对应的模块并返回if (r != NULL)Py_INCREF(r);err:Py_XDECREF(globals);Py_XDECREF(builtins);Py_XDECREF(import);return r;
}

此时获取导入的site,该文件位于Lib/site.py文件,该site.py文件在导入的时候,会执行main()函数,

def main():"""Add standard site-specific directories to the module search path.This function is called automatically when this module is imported,unless the python interpreter was started with the -S flag."""global ENABLE_USER_SITEabs_paths()known_paths = removeduppaths()known_paths = venv(known_paths)if ENABLE_USER_SITE is None:ENABLE_USER_SITE = check_enableusersite()known_paths = addusersitepackages(known_paths)known_paths = addsitepackages(known_paths)setquit()setcopyright()sethelper()enablerlcompleter()aliasmbcs()execsitecustomize()if ENABLE_USER_SITE:execusercustomize()

该函数就是将site-packages中模块导入到sys.path中,其中执行的细节过程可以通过main函数的各个函数继续查看,至此,_Py_InitializeEx_Private初始化函数基本执行完成。

总结

Python启动后的基本的环境和变量已经基本上准备完成,相关内建函数导入,扩展的第三方模块导入完成,接下来就开始编译和执行Python脚本。

Python3.5源码分析-sys模块及site模块导入相关推荐

  1. ceph-deploy源码分析(三)——mon模块 转

    ceph-deploy源码分析(三)--mon模块 原文: http://www.hl10502.com/2017/06/19/ceph-deploy-mon/#more ceph-deploy的mo ...

  2. webpack 源码分析(四)——complier模块

    webpack 源码分析(四)--complier模块 上一篇我们看到,webpack-cli 通过 yargs 对命令行传入的参数和配置文件里的配置项做了转换包装,然后传递给 webpack 的 c ...

  3. Python3.5源码分析-内建模块builtins初始化

    Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3模块初始化与加载 Python的模块分为内建的模 ...

  4. python3.5源码分析-启动与虚拟机

    Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3启动流程概述 本文基于python3分析其基本的 ...

  5. Python3.5源码分析-内存管理

    Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的内存管理概述 python提供了对内存的垃圾收 ...

  6. Python3.5源码分析-Dict概述

    Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的Dict对象 在生成d = {}和d['1'] ...

  7. Python3.5源码分析-List概述

    Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的List对象 list对象是一个变长对象,在运 ...

  8. Python3.5源码分析-垃圾回收机制

    Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的垃圾回收概述 随着软硬件的发展,大多数语言都已 ...

  9. python3.7源码分析-字典

    python字典 Dictionary object implementation using a hash table ,通过描述可知,python的字典就是实现了一个hash表. Python字典 ...

最新文章

  1. linux su、su -和sudo的区别
  2. ABAP检查日期and时间合法性的函数
  3. ArcGIS实验教程——实验十三:栅格空间插值分析
  4. [XSY] 简单的数论题(数学、构造)
  5. 文件字符串变量插入linux,Linux Shell脚本实现在文件指定的行插入字符串
  6. html 地址 点击召唤高德,高德地图api 点聚合+海量点+点击事件(根据地区或坐标进行定位)...
  7. python 人数取整_在python中如何取整到10的最高倍数?
  8. 【csdn】markdown使用教程
  9. php缓存静态化设计,PHP使用OB缓存实现静态化功能示例
  10. php高并发状态下文件的读写
  11. EM310指令集及使用
  12. Java开发webservice接口
  13. 试用Windows Server 2008
  14. UDS(统一诊断服务)的理解——0x19服务
  15. MyBatis14 缓存
  16. table表格中使用插槽
  17. 如何使用python下载网站上的视频
  18. Web攻防--基础入门--特定漏洞
  19. 指针式万用表使用与原理
  20. 网络空间安全导论-第一章习题

热门文章

  1. 谷歌发布 RLDS,在强化学习生成、共享和使用数据集
  2. 遏制企业数据泄露之殇,大咖切磋云安全的攻防之道
  3. 当 AI 闯入法律界,第一步是当律师的得力助手
  4. 老码农90%的程序猿都是瞎努力,这份路线教你成为高手!
  5. 一文读懂:GoogleNet的Inception从v1到v4的演变
  6. 有望替代卷积神经网络?微软最新研究提基于关系网络的视觉建模
  7. 2018最后一战:25天编程PK赛!
  8. 如何快速优化机器学习的模型参数
  9. 是男人就过8题!楼教主出题,请接招!
  10. 无语!你竟然连CompletableFuture都不知道,还天天说在jdk8原地踏步~