来自相关包的未知 python 导入行为

Unknown python import behaviour from relative package

我偶然发现了一些奇怪的 python (2.7) 导入行为,虽然很容易解决,但让我摸不着头脑。

给定以下文件夹结构:

test/
    __init__.py
    x.py
    package/
        __init__.py
        x.py

其中 test/package/__init__.py 包含以下内容

from .. import x
print x
from .x import hello
print x
print x.hello

而test/package/x.py包含以下内容

hello = 1

为什么 REPL 的 运行 import test.package 会产生以下输出?

<module 'test.x' from 'test/x.pyc'>
<module 'test.package.x' from 'test/package/x.pyc'>
1

我本来希望 x 引用顶级 x 模块,但是第二个导入所做的是导入整个本地 x 模块(不仅仅是 hello 如我所料),有效地践踏了第一次导入。

谁能在这里解释导入的机制?

from .x import name 意识到 test.package.x 需要成为一个模块。然后检查 sys.modules 中的相应条目;如果在那里找到,则 sys.modules['test.package.x'].hello 被导入到调用模块中。

但是,如果sys.modules['test.package.x']还不存在,则加载该模块;并且作为加载的最后一步,sys.modules['test.package'].x 被设置为指向新加载的模块,即使您明确没有要求它。因此,第二个导入覆盖了第一个导入的名称。

这是设计使然,否则

import foo.bar.baz
foo.bar.baz.x()

from foo.bar import baz
baz.x() 

不能互换。


我无法在 Python 2 文档中找到关于此行为的良好文档,但 Python 3 behaviour 在这种情况下基本相同:

When a submodule is loaded using any mechanism (e.g. importlib APIs, the import or import-from statements, or built-in __import__()) a binding is placed in the parent module’s namespace to the submodule object. For example, if package spam has a submodule foo, after importing spam.foo, spam will have an attribute foo which is bound to the submodule.

[...]

The invariant holding is that if you have sys.modules['spam'] and sys.modules['spam.foo'] (as you would after the above import), the latter must appear as the foo attribute of the former.