2

Python 3 解释器引发此异常的确切规则是什么?

有很多关于这个的问题,有很好的答案,但我找不到一个对发生这种异常的情况给出清晰、一般和逻辑上精确的定义。

文档似乎也不清楚。它说:

例外ImportError

当 import 语句找不到模块定义或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 语句中提到的唯一模块或名称是tand d,它们都被清楚地找到了。如果文档暗示未找到模块中的某些名称d肯定不明显;最重要的是,我希望它会引发NameError: name ... is not defined异常而不是ImportError.

4

3 回答 3

3

如果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 正在做什么。

  1. 在加载t.py时,它首先看到的是from testpack import d.
  2. 此时,Python 执行d.py文件以加载该模块。
  3. 但它发现的第一件事是from testpack import t
  4. 它已经加载了t.py一次,但是作为主脚本的 t 与作为模块的 t 不同,因此它会尝试t.py再次加载。
  5. 它首先看到的是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而不是将其作为脚本运行):

  1. 它开始导入 t。当它这样做时,它暂时将模块标记code.t为已导入,即使它还没有完成导入。
  2. 它发现它必须做import code.d,所以它运行 d。
  3. 在 d 中,它找到了import code.t,但由于code.t已经标记为已导入,它不会尝试再次导入它。
  4. 由于 d 没有实际使用就完成了t,它可以返回并完成加载t。没问题。

关键区别在于名称td在这里不能直接相互访问;它们由 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.td而d执行完后,它可以返回并完成t执行。

重申一下,这个故事的主要寓意是不要使用循环导入。它会导致各种头痛。相反,将公共代码分解到两个模块导入的第三个模块中。

于 2012-09-23T23:14:36.807 回答
1
from abc import xyz

相当于做

xyz = __import__('abc').xyz

因为如果你只是import abc,abc.xyz没有单独的导入就不会存在(除非abc/__init__.py包含显式importfor xyz),所以你看到的是预期的行为。

于 2012-09-24T00:17:47.320 回答
0

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

于 2012-09-24T07:10:13.827 回答