Python:从模块中循环导入成员
假设我有以下代码Python:从模块中循环导入成员,python,python-import,circular-dependency,Python,Python Import,Circular Dependency,假设我有以下代码 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" 正如在这篇文章中所解释的,它将起作用。(简单的解释是,假设我们从python repl调用import foo,当第一次遇到import bar时,p
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"
正如在这篇文章中所解释的,它将起作用。(简单的解释是,假设我们从python repl调用import foo
,当第一次遇到import bar
时,python将bar
放入sys.modules
并执行bar.py
,当遇到import foo
时,因为foo
已经在sys.modules
中,因此rt语句直接返回,即使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
$python foo.py
回溯(最近一次呼叫最后一次):
文件“foo.py”,第1行,在
从条形图导入xyz
文件“/Users/yxiong/bar.py”,第1行,在
从foo进口abc
文件“/Users/yxiong/foo.py”,第1行,在
从条形图导入xyz
导入错误:无法导入名称xyz
这里值得注意的是,python在从bar import 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
我的问题是,在这些步骤中到底发生了什么。具体地说,当python看到来自foo import abc的语句时,它会做什么?在这些框架中,首先python尝试加载/编译foo
模块(称为\uuu main\uuu
,只编译一次,但将执行两次):
但是bar
尝试加载/编译foo
并导入abc
,我们在sys.modules
中已经看到了。我们又回到了最初的进口:
File "/Users/yxiong/foo.py", line 1, in <module>
from bar import 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
ctrl-d
下一个实验:
cat > main.py
print('executing ' + __name__)
import foo
ctrl-d
还有一个有趣的问题。谢谢@Aaron。我做了另一个实验:从python repl运行import foo
,这次它在cannotimport name abc
(比从命令行运行python foo.py
少一帧)失败。正如您所解释的,在命令行中运行时,foo.py
首先作为\uuuu main\uuuu
模块运行,这就是为什么python在bar.py
遇到foo
时再次尝试导入foo的原因,foo
还不在sys.modules
中。另一方面,如果从repl运行,foo
在sys.modules
中,因此python声称失败,而没有再次尝试导入它。编辑以澄清,因为我打算通知它只导入一次。实际上我不同意。如果我向这两个文件中添加print\uuuuu file\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;如果从repl运行,则仅打印两个foo.py foo
和bar.py bar
。这意味着当在命令行中运行时,foo
确实被导入了两次,第一次作为\uuuu main\uuuu
导入,第二次作为foo
导入。如前所述,“执行脚本在名为\uuu main\uuuu
的模块中运行,以自己的名称导入脚本将创建一个与\uuu main\uu
无关的新模块。”
cat > foo.py
print('executing ' + __name__)
from bar import xyz
def abc(n):
return xyz(n-1) if n>0 else "abc"
cat > bar.py
print('executing ' + __name__)
from foo import abc
def xyz(n):
return abc(n-1) if n>0 else "xyz"
python foo.py
cat > main.py
print('executing ' + __name__)
import foo
python main.py