如果我的目录结构如下:
.
└── pkg
├── A.py
├── B.py
├── C.py
├── __init__.py
└── test
└── script.py
script.py
包含的位置:
import pkg.B
import pkg.A
print pkg.A.test()
A.py
:
import pkg.C
def test():
return pkg.B.test()
B.py
:
def test():
return 'AAAA'
C.py
:
def test3():
return 'C.test3'
并且__init__.py
为空。
如果A.py
导入pkg.C
,则代码有效。如果我注释掉那个导入,那么它失败了:
Traceback (most recent call last):
File "pkg/test/script.py", line 9, in <module>
print pkg.A.test()
File "/Users/X/Desktop/importtest/pkg/A.py", line 4, in test
return pkg.B.test()
NameError: global name 'pkg' is not defined
只要在import pkg.C
中导入import pkg
,将pkg.B
更改为仅script.py
。
如果我从pkg.B
注释掉script.py
的导入,那么如果我import pkg
或import pkg.C
A.py
,那么它就不会有所作为我收到一个错误:
Traceback (most recent call last):
File "pkg/test/script.py", line 10, in <module>
print pkg.A.test()
File "/Users/X/Desktop/importtest/pkg/A.py", line 4, in test
return pkg.B.test()
AttributeError: 'module' object has no attribute 'B'
这是我期望的行为。
所以基本问题是,如果在pkg.B.test()
中导入A.py
,pkg.B
导入pkg.B
,script.py
可以A.py
访问{{1}} }和{{1}}导入其他子模块?
我还不清楚这里工作的确切机制是什么。对于描述导入逻辑的好文章的解释或指示将是最受欢迎的。
答案 0 :(得分:1)
这个问题有点陈旧,但在遇到类似问题时我偶然发现了它。这就是我所理解的事情:
我们首先需要了解的是,modules are loaded only once!这意味着,例如,如果我们有:
X.py
:
import Z
import Y
blah blah
Y.py
:
import Z
blah bloo
运行X.py
将为我们提供以下内容:
import Y
的结果)。import Z
是模块Y
中的第一行,但模块Z
是。{
没有再次加载。注意:无论如何,模块是否已加载,模块的名称是导入的进入当前命名空间,使其可以访问但它们都引用相同的模块对象!! 。
导入子模块(例如pkg.A
)时,实质上是加载包pkg
__init__.py
模块,另外,加载A.py模块。但是你正在做的是将子模块作为属性添加到包的模块。即:
>>> import pkg
>>> hasattr(pkg, 'A')
False
重启Python会话后:
>>> import pkg.A
>>> hasattr(pkg, 'A')
True
因此,在script.py
执行import pkg.B
时,pkg
模块已加载,并且属性B
已添加到其“{1}}中。模块对象。当A.py
导入pkg.C
时,pkg
未加载,因为它已加载,而是将名称pkg
导入A.py
引用script.py
中导入的同一模块对象时的命名空间。由于属性B
已添加到该对象(script.py
)pkg.B.test
成功,即使它已在A.py
中执行。