1

我知道 Python 不鼓励任何可能使您进入循环导入的情况。但我想了解 Python 的内部原理,为什么 from-imports 在循环导入情况下似乎比正常导入更不宽容。

例如,此代码编译:

# main.py
import CommonUtil

# commonutil.py
import util
class CommonUtil:
    # some code that uses util.Util
    pass

# util.py
import commonutil
class Util:
    # some code that uses commonutil.CommonUtil
    pass

但是这段代码没有:

# main.py
import CommonUtil

# commonutil.py
import util
class CommonUtil:
    # some code that uses util.Util
    pass

# util.py
from commonutil import CommonUtil
class Util:
    # some code that uses CommonUtil
    pass

Traceback (most recent call last):
  File "main.py", line 1, in <module>
    import CommonUtil
  File "commonutil.py", line 1, in <module>
    import util
  File "util.py", line 1, in <module>
    from commonutil import CommonUtil
ImportError: cannot import name CommonUtil

只要您在所有导入完成之前不尝试使用相关类,就不会遇到编译器错误。但是当你尝试做一些混叠时,它就会失败。有人可以解释一下 Python 内部发生了什么,导致这个错误只有在使用 from-import 时才会出现?其次,有什么简单的方法可以解决这个问题吗?(除了明显的“将共享代码拉到第三个模块”之外,无论如何我都可能会这样做。)

4

2 回答 2

2

模块从上到下执行。当第一次看到导入时,当前模块的执行被暂停,以便可以导入其他模块。当另一个模块尝试导入第一个模块时,它会获得对当前部分执行的模块的引用。由于位于导入其他模块之后的代码尚未执行,因此其中包含的任何名称都不存在。

主文件

import a

一个.py

var1 = 'foo'
import b
var2 = 'bar'

b.py

import a
print a.var1 # works
print a.var2 # fails

解决方法是在执行完成之前不访问导入模块中的名称。

于 2011-09-29T01:45:45.560 回答
1

请参阅http://effbot.org/zone/import-confusion.htm#circular-imports了解正在发生的事情。

我假设您启动 main.py 文件。Python 将首先尝试加载commonutil. 它将创建一个模块对象,并在遇到它们的定义时开始用类和函数以及全局变量填充它。第一条语句是导入,所以现在 python 创建util模块并开始填充它。公共模块存在,但为空。在第一个版本中,您不会在加载时访问任何 commonutil 对象,所以一切都很好。在第二个中,您尝试在 commonutil 中获取当前不存在的特定变量。如果你f(commonutil.CommonUtil)在第一个版本中使用过类似的东西,它也会崩溃。

于 2011-09-29T01:51:48.663 回答