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_ENDIAN
SET_SYS_FROM_STRING("byteorder",
PyUnicode_FromString("big")); // 大端排序
#else
SET_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_THREAD
SET_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_copy
if (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;
#else
PyOS_sighandler_t oldhandler;
oldhandler = signal(sig, handler); // 设置信号量
#ifdef HAVE_SIGINTERRUPT
siginterrupt(sig, 1);
#endif
return oldhandler;
#endif
}
void
PyOS_InitInterrupts(void)
{
PyObject *m = PyImport_ImportModule("_signal"); // 导入_signal
if (m) {
Py_DECREF(m);
}
}
...
static void
initsigs(void)
{
#ifdef SIGPIPE
PyOS_setsig(SIGPIPE, SIG_IGN);
#endif
#ifdef SIGXFZ
PyOS_setsig(SIGXFZ, SIG_IGN);
#endif
#ifdef SIGXFSZ
PyOS_setsig(SIGXFSZ, SIG_IGN);
#endif
PyOS_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__ module
if (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); // 设值list
if (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); // 导入builtins
if (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);
}
else
import = PyObject_GetAttr(builtins, import_str);
if (import == NULL)
goto err;
/* Call the __import__ function with the proper argument list
Always 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的modules
r = 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_SITE
abs_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脚本。