假设我有以下代码。
foo.py
------
import bar
def abc(n):
return bar.xyz(n-1) if n>0 else "abc"
bar.py
------
import foo
def xyz(n):
return foo.abc(n-1) if n>0 else "xyz"
正如本文Circular (or cyclic) imports in Python中所述,它会起作用。 (简短的解释是,假设我们从python repl调用import foo
,首次遇到import bar
时,python将bar
放入sys.modules
并执行bar.py
,并且遇到import foo
时,由于foo
已经在sys.modules
,因此即使foo
模块不完整,导入语句也会直接返回。)
现在,如果我将代码更改为以下内容:
foo.py
------
from bar import xyz
def abc(n):
return xyz(n-1) if n>0 else "abc"
bar.py
------
from foo import abc
def xyz(n):
return abc(n-1) if n>0 else "xyz"
导入将失败:
$ python foo.py
Traceback (most recent call last):
File "foo.py", line 1, in <module>
from bar import xyz
File "/Users/yxiong/bar.py", line 1, in <module>
from foo import abc
File "/Users/yxiong/foo.py", line 1, in <module>
from bar import xyz
ImportError: cannot import name xyz
值得注意的是,在from bar import xyz
的第二次尝试中,python似乎失败了。
我的问题是,这些步骤究竟发生了什么。具体来说,当python看到from foo import abc
语句时会做什么?
答案 0 :(得分:0)
遍历框架,首先Python尝试加载/编译foo
模块(称为__main__
,仅编译一次,但将执行两次):
Traceback (most recent call last):
File "foo.py", line 1, in <module>
from bar import xyz # first attempt to import xyx, but it depends on abc
Python尝试执行import语句。
因此,由于Python只加载/编译模块一次(除非使用reload
),它会查找sys.modules
,因为它不在那里,它会尝试加载/编译bar
模块导入xyz
。
File "/Users/yxiong/bar.py", line 1, in <module>
from foo import abc # so we attempt to import abc, but it depends on xyz
但是bar
尝试加载/编译foo
并导入abc
,我们看到它已经在sys.modules
中。我们回到原来的导入:
File "/Users/yxiong/foo.py", line 1, in <module>
from bar import xyz
我们得到了ImportError:
ImportError: cannot import name xyz
让我们从Unix的终端凭经验证明:
cat > foo.py
print('executing ' + __name__)
from bar import xyz
def abc(n):
return xyz(n-1) if n>0 else "abc"
CTRL-d
cat > bar.py
print('executing ' + __name__)
from foo import abc
def xyz(n):
return abc(n-1) if n>0 else "xyz"
CTRL-d
python foo.py
下一个实验:
cat > main.py
print('executing ' + __name__)
import foo
CTRL-d
python main.py