美文网首页
大师兄的Python源码学习笔记(三十一): 运行环境初始化(三

大师兄的Python源码学习笔记(三十一): 运行环境初始化(三

作者: superkmi | 来源:发表于2021-09-03 09:06 被阅读0次

    大师兄的Python源码学习笔记(三十): 运行环境初始化(二)
    大师兄的Python源码学习笔记(三十二): 运行环境初始化(四)

    2. 创建sys module
    2.1 sys module的备份
    • __builtin__ module之后,Python会用同样的流程设置sys module,并像设置interp->builtins一样设置interp->sysdict
    Python\pylifecycle.c
    
    static _PyInitError
    new_interpreter(PyThreadState **tstate_p)
    {
        PyInterpreterState *interp;
        PyThreadState *tstate, *save_tstate;
        PyObject *bimod, *sysmod;
        _PyInitError err;
       ... ...
        sysmod = _PyImport_FindBuiltin("sys", modules);
        if (sysmod != NULL) {
            interp->sysdict = PyModule_GetDict(sysmod);
            if (interp->sysdict == NULL)
                goto handle_error;
            Py_INCREF(interp->sysdict);
            PyDict_SetItemString(interp->sysdict, "modules", modules);
        ... ...
    }
    
    • 通过_PyImport_FindBuiltin创建sys module,并通过_PyImport_FindExtensionObjectEx将其备份:
    Python\import.c
    
    PyObject *
    _PyImport_FindBuiltin(const char *name, PyObject *modules)
    {
        PyObject *res, *nameobj;
        nameobj = PyUnicode_InternFromString(name);
        if (nameobj == NULL)
            return NULL;
        res = _PyImport_FindExtensionObjectEx(nameobj, nameobj, modules);
        Py_DECREF(nameobj);
        return res;
    }
    
    Python\import.c
    
    static PyObject *extensions = NULL;
    ... ...
    PyObject *
    _PyImport_FindExtensionObjectEx(PyObject *name, PyObject *filename,
                                    PyObject *modules)
    {
        PyObject *mod, *mdict, *key;
        PyModuleDef* def;
        if (extensions == NULL)
            return NULL;
        key = PyTuple_Pack(2, filename, name);
        if (key == NULL)
            return NULL;
        def = (PyModuleDef *)PyDict_GetItem(extensions, key);
        Py_DECREF(key);
        if (def == NULL)
            return NULL;
        if (def->m_size == -1) {
            /* Module does not support repeated initialization */
            if (def->m_base.m_copy == NULL)
                return NULL;
            mod = _PyImport_AddModuleObject(name, modules);
            if (mod == NULL)
                return NULL;
            mdict = PyModule_GetDict(mod);
            if (mdict == NULL)
                return NULL;
            if (PyDict_Update(mdict, def->m_base.m_copy))
                return NULL;
        }
        else {
            if (def->m_base.m_init == NULL)
                return NULL;
            mod = def->m_base.m_init();
            if (mod == NULL)
                return NULL;
            if (PyObject_SetItem(modules, name, mod) == -1) {
                Py_DECREF(mod);
                return NULL;
            }
            Py_DECREF(mod);
        }
        if (_PyState_AddModule(mod, def) < 0) {
            PyMapping_DelItem(modules, name);
            Py_DECREF(mod);
            return NULL;
        }
        if (Py_VerboseFlag)
            PySys_FormatStderr("import %U # previously loaded (%R)\n",
                              name, filename);
        return mod;
    
    }
    
    • 从上一段代码可以看出,Python内部维护了一个全局变量extensions,它是一个PyDictObject对象,用于维护所有已经被Python加载的module中的PyDictObject的一个备份。
    • 当Python系统的module集合中的某个标准扩展module被删除后不久又被重新加载时,Python不需要再次初始化这些module,而是从extensions中备份的PyDictObject对象来创建一个新的module即可。
    • 这也说明了为什么Python中的标准扩展module是不会在运行时动态改变的。
    • 在完成了__builtin__sys两个module对象的设置之后,PyInterpreterState对象PyThreadState对象在内存中如上图所示。
    • 注意,与之前的源码相同,在上图中__builtins__sys指向的是PyDictObject对象,而不是PyModuleObject对象。
    2.2 设置module的搜索路径
    • Python在创建了sys module之后,会在其中设置一个搜索module时的默认搜索路径集合
    Python\sysmodule.c
    
    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)
            Py_FatalError("can't assign sys.path");
        Py_DECREF(v);
    }
    
    Python\sysmodule.c
    
    static PyObject *
    makepathobject(const wchar_t *path, wchar_t delim)
    {
        int i, n;
        const wchar_t *p;
        PyObject *v, *w;
    
        n = 1;
        p = path;
        while ((p = wcschr(p, delim)) != NULL) {
            n++;
            p++;
        }
        v = PyList_New(n);
        if (v == NULL)
            return NULL;
        for (i = 0; ; i++) {
            p = wcschr(path, delim);
            if (p == NULL)
                p = path + wcslen(path); /* End of string */
            w = PyUnicode_FromWideChar(path, (Py_ssize_t)(p - path));
            if (w == NULL) {
                Py_DECREF(v);
                return NULL;
            }
            PyList_SET_ITEM(v, i, w);
            if (*p == '\0')
                break;
            path = p+1;
        }
        return v;
    }
    
    Python\sysmodule.c
    
    int
    _PySys_SetObjectId(_Py_Identifier *key, PyObject *v)
    {
        PyThreadState *tstate = PyThreadState_GET();
        PyObject *sd = tstate->interp->sysdict;
        if (v == NULL) {
            if (_PyDict_GetItemId(sd, key) == NULL)
                return 0;
            else
                return _PyDict_DelItemId(sd, key);
        }
        else
            return _PyDict_SetItemId(sd, key, v);
    }
    
    • makepathobject中,Python会创建一个PyListObject对象,这个list中包含了一组PyStringObject对象,每一个PyStringObject对象的内容就是一个module的搜索路径。
    • 最终,这个PyListObject对象会在_PySys_SetObjectId中被插入到interp->sysdict,也就是sys module维护的PyDictObject对象中。
    • Python随后还会进行一些琐碎的动作,其中包括初始化import环境,初始化内建异常。
    Python\pylifecycle.c
    
    _PyInitError
    _Py_InitializeCore_impl(PyInterpreterState **interp_p,
                            const _PyCoreConfig *core_config)
    {
        PyInterpreterState *interp;
        _PyInitError err;
    
        ... ...
        err = _PyImport_Init(interp);
        ... ...
    }
    
    Python\pylifecycle.c
    
    static _PyInitError
    new_interpreter(PyThreadState **tstate_p)
    {
        PyInterpreterState *interp;
        PyThreadState *tstate, *save_tstate;
        PyObject *bimod, *sysmod;
        _PyInitError err;
    
        ... ...
    
        bimod = _PyImport_FindBuiltin("builtins", modules);
        if (bimod != NULL) {
            interp->builtins = PyModule_GetDict(bimod);
            if (interp->builtins == NULL)
                goto handle_error;
            Py_INCREF(interp->builtins);
        }
        else if (PyErr_Occurred()) {
            goto handle_error;
        }
    
        /* initialize builtin exceptions */
        _PyExc_Init(bimod);
    
        ... ...
    }
    

    相关文章

      网友评论

          本文标题:大师兄的Python源码学习笔记(三十一): 运行环境初始化(三

          本文链接:https://www.haomeiwen.com/subject/ihpniltx.html