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

为什么Python在使用from imports时对循环导入更严格?,python,python-import,python-internals,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: # so

我知道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
#main.py
导入CommonUtil
#commonutil.py
导入util
类CommonUtil:
#一些使用util.util的代码
通过
#util.py
从commonutil导入commonutil
类Util:
#一些使用CommonUtil的代码
通过
回溯(最近一次呼叫最后一次):
文件“main.py”,第1行,在
导入CommonUtil
文件“commonutil.py”,第1行,在
导入util
文件“util.py”,第1行,在
从commonutil导入commonutil
ImportError:无法导入名称CommonUtil

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

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

main.py a、 派克 b、 派克 解决方法是在导入模块的执行完成之前,不要访问该模块中的名称。

有关发生的情况的解释,请参阅


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

在您的第一个示例中,
import commonutil.commonutil
应该引发一个
ImportError
,因为
commonutil
不是一个模块。您是对的。我的意思是
import commonutil
import util
——我已经做了这些更改。
import a
var1 = 'foo'
import b
var2 = 'bar'
import a
print a.var1 # works
print a.var2 # fails