Python 3解释器引发此异常的准确规则是什么?
有很多关于这方面的SO问题,并且有很好的答案,但是我找不到一个在发生此异常时给出明确,一般和逻辑上精确定义的情况。
文档似乎也不清楚。它说:
例外
ImportError
导入语句无法找到时引发 模块定义或
from ... import
无法找到名称时 那是要导入的。
但这似乎与以下示例不一致。
我的意思是要求一般性定义而不是具体案例,但为了澄清我的顾虑,这是一个例子:
# code/t.py:
from code import d
# code/d.py
from code import t
从命令行运行模块t.py
会产生ImportError: cannot import name d
。
另一方面,以下代码不会引发异常:
# code/t.py:
import code.d
# code/d.py
import code.t
任何时候,__init__.py
都是空的。
在此示例中,import语句中提到的唯一模块或名称是t
和d
,并且它们都清楚地找到了。如果文档暗示找不到<{em> d
模块中的某个名称,那肯定不是很明显;最重要的是,我希望它会引发NameError: name ... is not defined
例外而不是ImportError
。
答案 0 :(得分:3)
如果abc
是一个包,而xyz
是一个模块,并且abc
的{{1}}定义的__init__.py
不包含__all__
}},那么你将无法xyz
,但你仍然可以from abc import xyz
。
编辑:简短的回答是:您的问题是您的导入是循环的。模块t和d尝试相互导入。这不行。不要这样做。我将在下面解释整个事情,但解释很长。
要理解为什么它会产生ImportError,请尝试遵循代码执行。如果您查看完整的回溯而不是最后的部分,您可以看到它正在做什么。使用你的设置我得到这样的追溯(我称之为“testpack”而不是“code”):
import abc.xyz
你可以看到Python在这里做了什么。
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
时,首先看到的是t.py
。from testpack import d
文件以加载该模块。d.py
。from testpack import t
一次,但是因为主脚本与作为模块的t不同,所以它会尝试再次加载t.py
。t.py
,这意味着它应该尝试加载from testpack import d
。 。 。但是已经 尝试在步骤2中加载d.py
。由于尝试导入d.py
导致重新尝试再次导入d
,Python意识到它可以'import d
并抛出ImportError。步骤4在这里有点异常,因为你直接在包中运行了一个文件,这不是通常的做事方式。有关导入模块与直接运行模块的原因不同的说明,请参阅this question。如果您尝试导入 d
(使用t
),Python会更快地实现循环,并且您可以获得更简单的回溯:
from testpack import t
请注意,此处的错误是无法导入 t 。它知道它不能,因为当我告诉它导入t时,它发现自己循环返回导入t。在您的原始示例中,它没有注意到它运行了两次t.py,因为第一次是主脚本而第二次是导入,所以又花了一步并尝试再次导入d。
现在,为什么在>>> 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
执行此操作时不会发生这种情况?答案只是因为你实际上没有尝试使用导入的模块在这种情况下,它发生如下(我将解释为你做import code.d
而不是运行它作为一个脚本):
from code import t
标记为已导入,即使尚未完成导入。code.t
,所以它运行d。import code.d
,但由于import code.t
已标记为已导入,因此不会尝试再次导入。code.t
的情况下完成,因此可以返回并完成加载t
。没问题。关键区别在于,t
和t
名称在此处无法直接访问;它们是由包d
调解的,因此Python实际上不必完成“决定它是什么”,直到实际使用它为止。使用code
,因为必须将值赋给变量from code import t
,Python必须立即知道它是什么。
您可以看到问题,但如果您使t
看起来像这样:
d.py
现在,在步骤2之后,在运行d时,它实际上尝试访问半导入模块t。这将引发AttributeError,因为该模块尚未完全导入,因此尚未附加到包import code.t
print code.t
。
请注意,只要在code
完成运行之后才使用code.t
就行了。这可以在d
中正常工作:
d.py
您可以稍后致电import code.t
def f():
print code.t
,它会起作用。原因是它不需要在f
完成执行之后使用code.t
,并且在完成执行之后,它可以返回并完成执行t。
重申一下,故事的主要道德是不要使用循环导入。它会导致各种令人头疼的问题。相反,将公共代码分解为由两个模块导入的第三个模块。
答案 1 :(得分:1)
from abc import xyz
相当于做
xyz = __import__('abc').xyz
如果你只是import abc
,abc.xyz
在没有单独导入的情况下就不会存在(除非abc/__init__.py
包含import
的明确xyz
,你看到的是预期的行为。
答案 2 :(得分:0)
问题是abc
是一个预定义的标准库模块,只是创建一个同名的子目录,其中包含__init__.py
并不会改变这一事实。通过将__init__.py
文件所在的文件夹重命名为不同的文件夹(即def
),将包的名称更改为其他名称,然后import
的两种形式都应该无误地执行。< / p>