使用from-imports时,为什么Python对循环导入更严格?

时间:2011-09-29 01:36:17

标签: python python-import python-internals

我知道Python不鼓励任何可以让你进入循环导入的情况。但是我想了解Python内部原因,为什么在循环导入情况下,进口似乎比普通进口任意减少宽容。

例如,此代码编译:

# 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时才能解决问题?其次,这有什么简单的方法吗? (除了显而易见的“将共享代码拉到第三个模块”之外,我可能还会这样做。)

2 个答案:

答案 0 :(得分:2)

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

main.py

import a

a.py

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

b.py

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

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

答案 1 :(得分:1)

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

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