如果abc是一个包而xyz是一个模块,并且如果abc的__init__.py定义了一个不包含__all__的__all__,那么你将无法做到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 步在这里有点反常,因为您直接在包中运行了一个文件,这不是通常的处理方式。请参阅this question,了解为什么导入模块与直接运行模块不同。如果您尝试导入 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 在此处不能直接相互访问;它们由包code 调解,因此在实际使用之前,Python 实际上不必完成“确定 t 是什么”。对于from code import t,由于必须将值分配给变量t,Python 必须立即知道它是什么。
你可以看到问题,但如果你让d.py看起来像这样:
import code.t
print code.t
现在,在第 2 步之后,在运行 d 时,它实际上尝试访问半导入的模块 t。这将引发 AttributeError,因为模块尚未完全导入,因此尚未附加到包 code。
请注意,只要在 d 完成运行之后才使用 code.t 就可以了。这将在d.py 中正常工作:
import code.t
def f():
print code.t
您可以稍后致电f,它会起作用。原因是直到d执行完毕后才需要使用code.t,而d执行完毕后,可以返回执行t。
重申一下,这个故事的主要寓意是不要使用循环导入。它会导致各种头痛。相反,将公共代码分解到两个模块都导入的第三个模块中。