Python3.5源码分析-sys模块及site模块导入
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模块导入相关推荐
- ceph-deploy源码分析(三)——mon模块 转
ceph-deploy源码分析(三)--mon模块 原文: http://www.hl10502.com/2017/06/19/ceph-deploy-mon/#more ceph-deploy的mo ...
- webpack 源码分析(四)——complier模块
webpack 源码分析(四)--complier模块 上一篇我们看到,webpack-cli 通过 yargs 对命令行传入的参数和配置文件里的配置项做了转换包装,然后传递给 webpack 的 c ...
- Python3.5源码分析-内建模块builtins初始化
Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3模块初始化与加载 Python的模块分为内建的模 ...
- python3.5源码分析-启动与虚拟机
Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3启动流程概述 本文基于python3分析其基本的 ...
- Python3.5源码分析-内存管理
Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的内存管理概述 python提供了对内存的垃圾收 ...
- Python3.5源码分析-Dict概述
Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的Dict对象 在生成d = {}和d['1'] ...
- Python3.5源码分析-List概述
Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的List对象 list对象是一个变长对象,在运 ...
- Python3.5源码分析-垃圾回收机制
Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的垃圾回收概述 随着软硬件的发展,大多数语言都已 ...
- python3.7源码分析-字典
python字典 Dictionary object implementation using a hash table ,通过描述可知,python的字典就是实现了一个hash表. Python字典 ...
最新文章
- linux su、su -和sudo的区别
- ABAP检查日期and时间合法性的函数
- ArcGIS实验教程——实验十三:栅格空间插值分析
- [XSY] 简单的数论题(数学、构造)
- 文件字符串变量插入linux,Linux Shell脚本实现在文件指定的行插入字符串
- html 地址 点击召唤高德,高德地图api 点聚合+海量点+点击事件(根据地区或坐标进行定位)...
- python 人数取整_在python中如何取整到10的最高倍数?
- 【csdn】markdown使用教程
- php缓存静态化设计,PHP使用OB缓存实现静态化功能示例
- php高并发状态下文件的读写
- EM310指令集及使用
- Java开发webservice接口
- 试用Windows Server 2008
- UDS(统一诊断服务)的理解——0x19服务
- MyBatis14 缓存
- table表格中使用插槽
- 如何使用python下载网站上的视频
- Web攻防--基础入门--特定漏洞
- 指针式万用表使用与原理
- 网络空间安全导论-第一章习题