解释相对导入使用模块的_name_属性来确定模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它被设置为‘_main_’)然后,就像模块是顶级模块一样解析相对导入。,而不管模块实际位于文件系统上的位置。..相对进口依赖___名称__若要确定当前模块在包层次结构中的位置,请执行以下操作。在主模块中,___名称__总是‘_’,因此显式的相对导入总是失败的(因为它们只适用于包内的模块)。
为了解决这个问题,佩普366引入顶层变量__package__:通过添加一个新的模块级属性,如果使用-m切换。当按名称执行文件时,模块本身中的少量样板将允许相对导入工作。[.]当它[属性]存在时,相对导入将基于此属性而不是基于模块。___名称__属性。[.]当主模块由其文件名指定时,则包件属性将设置为无. [...] 当导入系统在没有_Package_SET(或将其设置为None)的模块中遇到显式相对导入时,它将计算并存储正确的值。(_name_.r分区(‘.’)[0]用于普通模和___名称__封装初始化模块)
(强调地雷)
如果__name__是'__main__', __name__.rpartition('.')[0]返回空字符串。这就是错误描述中存在空字符串文字的原因:SystemError: Parent module '' not loaded, cannot perform relative importif (PyDict_GetItem(interp->modules, package) == NULL) {
PyErr_Format(PyExc_SystemError,
"Parent module %R not loaded, cannot perform relative "
"import", package);
goto error;}
如果无法找到此异常,则cpython将引发此异常。package(包裹的名称)interp->modules(可从sys.modules)。自sys.modules是“将模块名称映射到已经加载的模块的字典”,现在很清楚在执行相对导入之前,父模块必须显式地绝对导入。.
注:的补丁第18018期增加另一个if块,将被执行以前上述守则:if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
PyErr_SetString(PyExc_ImportError,
"attempted relative import with no known parent package");
goto error;} /* else if (PyDict_GetItem(interp->modules, package) == NULL) {
...
*/
如果package(与上面