如果abc
是一个包并且xyz
是一个模块,如果abc
's__init__.py
定义了一个__all__
不包含的xyz
,那么你将无法做from abc import xyz
,但你仍然可以做import abc.xyz
。
编辑:简短的回答是:你的问题是你的进口是循环的。模块 t 和 d 尝试相互导入。这行不通。不要这样做。我将在下面解释整个事情,但解释很长。
要了解它为什么给出 ImportError,请尝试遵循代码执行。如果您查看完整的回溯,而不仅仅是最后一部分,您可以看到它在做什么。通过您的设置,我得到了这样的回溯(我将包称为“testpack”而不是“code”):
Traceback (most recent call last):
File "t.py", line 1, in <module>
from testpack import d
File "C:\Documents and Settings\BrenBarn\My Documents\Python\testpack\d.py", line 1, in <module>
from testpack import t
File "C:\Documents and Settings\BrenBarn\My Documents\Python\testpack\t.py", line 1, in <module>
from testpack import d
ImportError: cannot import name d
你可以在这里看到 Python 正在做什么。
- 在加载
t.py
时,它首先看到的是from testpack import d
.
- 此时,Python 执行
d.py
文件以加载该模块。
- 但它发现的第一件事是
from testpack import t
。
- 它已经加载了
t.py
一次,但是作为主脚本的 t 与作为模块的 t 不同,因此它会尝试t.py
再次加载。
- 它首先看到的是
from testpack import d
,这意味着它应该尝试加载d.py
。. . 但它已经在步骤 2中尝试重新加载d.py
。由于尝试导入d
导致再次尝试导入d
,Python 意识到它无法导入d
并抛出 ImportError。
第 4 步在这里有点异常,因为您直接在包中运行了一个文件,这不是通常的处理方式。请参阅此问题以了解为什么导入模块与直接运行模块不同。如果您尝试导入 t
(使用from testpack import t
),Python 会提前一步实现循环,并且您会获得更简单的回溯:
>>> from testpack import t
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
from testpack import t
File "C:\Documents and Settings\BrenBarn\My Documents\Python\testpack\t.py", line 1, in <module>
from testpack import d
File "C:\Documents and Settings\BrenBarn\My Documents\Python\testpack\d.py", line 1, in <module>
from testpack import t
ImportError: cannot import name t
请注意,这里的错误是它无法导入t。它知道它不能,因为当我告诉它导入 t 时,它发现自己再次循环返回导入 t。在您的原始示例中,它没有注意到它运行了 t.py 两次,因为第一次是主脚本,第二次是导入,所以它又走了一步并尝试再次导入 d。
现在,为什么当你这样做时不会发生这种情况import code.d
?答案只是因为您实际上并没有尝试使用导入的模块。在这种情况下,它发生如下(我将像您那样进行解释,from code import t
而不是将其作为脚本运行):
- 它开始导入 t。当它这样做时,它暂时将模块标记
code.t
为已导入,即使它还没有完成导入。
- 它发现它必须做
import code.d
,所以它运行 d。
- 在 d 中,它找到了
import code.t
,但由于code.t
已经标记为已导入,它不会尝试再次导入它。
- 由于 d 没有实际使用就完成了
t
,它可以返回并完成加载t
。没问题。
关键区别在于名称t
和d
在这里不能直接相互访问;它们由 package 调解code
,因此 Python 实际上不必在实际使用之前完成“确定 t 是什么”。使用from code import t
,由于必须将值分配给变量t
,Python 必须立即知道它是什么。
您可以看到问题,但如果您d.py
看起来像这样:
import code.t
print code.t
现在,在第 2 步之后,在运行 d 时,它实际上尝试访问半导入的模块 t。这将引发 AttributeError ,因为该模块尚未完全导入,因此尚未附加到 package code
。
请注意,只要在完成运行code.t
后才使用 就可以了。d
这将在以下情况下正常工作d.py
:
import code.t
def f():
print code.t
你可以f
稍后再打电话,它会工作的。原因是它执行完后才需要使用code.t
,d
而d执行完后,它可以返回并完成t执行。
重申一下,这个故事的主要寓意是不要使用循环导入。它会导致各种头痛。相反,将公共代码分解到两个模块导入的第三个模块中。