“ImportError:无法导入名称...” - 在“从...导出”而非直接导入时引发

时间:2012-09-23 23:11:51

标签: python import python-3.x importerror

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语句中提到的唯一模块或名称是td,并且它们都清楚地找到了。如果文档暗示找不到<{em> d模块中的某个名称,那肯定不是很明显;最重要的是,我希望它会引发NameError: name ... is not defined例外而不是ImportError

3 个答案:

答案 0 :(得分:3)

如果abc是一个包,而xyz是一个模块,并且abc的{​​{1}}定义的__init__.py不包含__all__ }},那么你将无法xyz,但你仍然可以from abc import xyz

编辑:简短的回答是:您的问题是您的导入是循环的。模块t和d尝试相互导入。这不行。不要这样做。我将在下面解释整个事情,但解释很长。

要理解为什么它会产生ImportError,请尝试遵循代码执行。如果您查看完整的回溯而不是最后的部分,您可以看到它正在做什么。使用你的设置我得到这样的追溯(我称之为“testpack”而不是“code”):

import abc.xyz

你可以看到Python在这里做了什么。

  1. 在加载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
  2. 此时,Python执行from testpack import d文件以加载该模块。
  3. 但它发现的第一件事是d.py
  4. 它已经加载from testpack import t一次,但是因为主脚本与作为模块的t不同,所以它会尝试再次加载t.py
  5. 它看到的第一件事是t.py,这意味着它应该尝试加载from testpack import d。 。 。但是已经 尝试在步骤2中加载d.py。由于尝试导入d.py导致重新尝试再次导入d,Python意识到它可以'import d并抛出ImportError。
  6. 步骤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而不是运行它作为一个脚本):

    1. 开始导入t。当它执行此操作时,它会临时将模块from code import t标记为已导入,即使尚未完成导入。
    2. 它发现它必须code.t,所以它运行d。
    3. 在d中,它会找到import code.d,但由于import code.t已标记为已导入,因此不会尝试再次导入。
    4. 由于d在没有实际使用code.t的情况下完成,因此可以返回并完成加载t。没问题。
    5. 关键区别在于,tt名称在此处无法直接访问;它们是由包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 abcabc.xyz在没有单独导入的情况下就不会存在(除非abc/__init__.py包含import的明确xyz,你看到的是预期的行为。

答案 2 :(得分:0)

问题是abc是一个预定义的标准库模块,只是创建一个同名的子目录,其中包含__init__.py并不会改变这一事实。通过将__init__.py文件所在的文件夹重命名为不同的文件夹(即def),将包的名称更改为其他名称,然后import的两种形式都应该无误地执行。< / p>