Bła*_*lik 9 python python-importlib
我注意到asyncio/init.py
从 python 3.6 开始使用以下构造:
from .base_events import *
...
__all__ = (base_events.__all__ + ...)
Run Code Online (Sandbox Code Playgroud)
该base_events
符号未在源代码中的任何位置导入,但模块仍包含它的局部变量。
我已经使用以下代码检查了这种行为,并将其放入一个旁边__init__.py
的虚拟对象中test.py
:
test = "not a module"
print(test)
from .test import *
print(test)
Run Code Online (Sandbox Code Playgroud)
不是模块
<module 'testpy.test' from 'C:\Users\MrM\Desktop\testpy\test.py'>
这意味着test
在使用星型导入后变量被隐藏了。
我稍微摆弄了一下,结果发现它不一定是一个星型 import,但它必须在一个 内__init__.py
,而且它必须是相对的。否则模块对象不会被分配到任何地方。
如果没有赋值,从一个不是 的文件运行上面的例子__init__.py
会引发一个NameError
.
这种行为从何而来?这是否已在某处的导入系统规范中进行了概述?__init__.py
必须以这种方式与众不同的原因是什么?它不在参考资料中,或者至少我找不到。
此行为在导入系统文档部分5.4.2 子模块中定义
当使用任何机制(例如 importlib API、import 或 import-from 语句或内置import ())加载子模块时,将在父模块的命名空间中放置到子模块对象的绑定。例如,如果包 spam 有一个子模块 foo,那么在导入 spam.foo 后,spam 将有一个属性 foo 绑定到子模块。
包命名空间包括在中创建的命名空间__init__.py
以及导入系统添加的额外内容。的原因是命名空间的一致性。
鉴于 Python 熟悉的名称绑定规则,这似乎令人惊讶,但它实际上是导入系统的一个基本特性。不变的是,如果你有 sys.modules['spam'] 和 sys.modules['spam.foo'] (就像你在上面导入之后那样),后者必须作为前者的 foo 属性出现。