如果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执行。
重申一下,这个故事的主要寓意是不要使用循环导入。它会导致各种头痛。相反,将公共代码分解到两个模块导入的第三个模块中。