我偶然发现了一些奇怪的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
模块(不仅仅是{{1}正如我所预期的那样,有效地践踏了第一次导入。
有人可以在这里解释导入的机制吗?
答案 0 :(得分:2)
T
意识到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()
不可互换。
我无法在Python 2文档中找到关于此行为的良好文档,但Python 3 behaviour在这种情况下基本相同:
使用任何机制(例如
from foo.bar import baz baz.x()
API,importlib
或import
-import
语句或内置from
)加载子模块时绑定放在父模块的命名空间中,放在子模块对象中。例如,如果包__import__()
具有子模块spam
,则在导入foo
后,spam.foo
将具有绑定到子模块的属性spam
。[...]
不变量持有是,如果您有
foo
和sys.modules['spam']
(就像上面的导入后那样),后者必须显示为前者的sys.modules['spam.foo']
属性。