从导入系统文档中:
当使用任何机制(例如importlib
API,import
或, 语句或内置__import__()
)加载子模块时,将在父模块的名称空间中放置与子模块对象的绑定。例如,如果packagespam
具有一个子模块foo
,则在导入后spam.foo
,spam
将具有foo
绑定到该子模块的属性。假设您具有以下目录结构:
spam/
__init__.py
foo.py
bar.py
并spam/__init__.py
包含以下几行:
from .foo import Foo
from .bar import Bar
然后执行以下命令,将名称绑定到foo
和bar
放在spam
模块中:
>>> import spam
>>> spam.foo
<module 'spam.foo' from '/tmp/imports/spam/foo.py'>
>>> spam.bar
<module 'spam.bar' from '/tmp/imports/spam/bar.py'>
鉴于Python熟悉的名称绑定规则,这似乎令人惊讶,但这实际上是导入系统的基本功能。不变的条件是,如果您有sys.modules['spam']
andsys.modules['spam.foo']
(如在上述导入之后一样),则后者必须作为foo
前者的属性出现。
如果这样做from testapp.api.utils import x
,import语句将不会加载utils
到本地名称空间中。但是,导入机制将 加载utils
到testapp.api
名称空间中,以使进一步的导入工作正常。碰巧您的情况testapp.api
也是本地名称空间,所以您会感到惊讶。