这是我下面的代码。
main.py:
import moduleA
print('It works!')
moduleA.py:
import moduleB
def functionA():
return 0
moduleB.py:
import moduleA
globalVariableFromModuleB = moduleA.functionA()
如果我运行它,我会收到错误消息:
$ python main.py
Traceback (most recent call last):
File "main.py", line 3, in <module>
import moduleA
File "/home/asa/bugs/moduleA.py", line 3, in <module>
import moduleB
File "/home/asa/bugs/moduleB.py", line 8, in <module>
globalVariableFromModuleB_1 = functionB()
File "/home/asa/bugs/moduleB.py", line 6, in functionB
return moduleA.functionA()
Q1:在我的情况下,模块 B 显式导入模块 A,因此我希望它能工作,但它没有。这是因为Python兑现进口并且不会做两次吗?但是为什么它不能从内存中取出已经兑现的模块A.functionA()而不是失败呢?因此,我想当前的行为是一个错误。
Q2:如果我删除行"globalVariableFromModuleB = moduleA.functionA()",只留下循环导入"import moduleA",那么我没有失败。因此,循环依赖在 Python 中是不是被禁止的。如果它们不工作,就像我的例子所示,他们允许什么?
Q3:如果我将"导入模块A">更改为"从模块A导入函数A",则主程序也无法正常工作,也不会失败,并显示另一条消息"导入错误:无法导入名称函数A"。
我还想在这里为不喜欢重新设计应用程序的人发布一个解决方法,就像我的情况一样。
解决方法(只是实验性地发现)。要在 main.py 中的"导入模块A">之前添加"导入模块B",即:
# main.py
import moduleB
import moduleA
print('It works!')
但是我不得不在代码中的这个导入中留下很长的评论,因为 main.py 没有直接使用模块 B 中的任何 API,所以它看起来很丑陋。
请问有人可以建议一些更好的如何解决这种情况并回答上面的 3 个问题吗?
python 中的循环导入是一个非常讨厌的"陷阱";这篇文章很好地解释了所有的来龙去脉 - 请考虑仔细阅读。
要解决这个问题,您只需制动循环 - 在您的情况下,您可以将导入模块A 放在模块B 中,因为它不需要(您已经在 main 中导入了 A)
要真正了解正在发生的事情,请考虑以下几点:
-
你做导入,python会加载代码 并逐行执行它并将 添加到系统模块 它知道它已经导入了
-
如果导入的包含另一个导入语句,Python 将加载并开始执行该代码,然后将模块名称添加到 sys.module
- 在您的情况下,sys.modules 同时包含模块 A 和模块 B,但由于模块 A 的执行被导入模块 B语句"中断",因此函数定义从未被执行,但模块点添加到 sys.modules => 属性错误:"模块"对象没有属性"函数 A">
希望这有帮助。
例如,我会在这里发布更复杂的情况(当每个模块在全局上下文中从另一个模块调用一个函数时),无需对程序进行重大重新设计即可工作:
main.py
import moduleA
print('Value=%s' % moduleA.functionA())
moduleA.py
globalVariableFromModuleA = 'globalA'
def functionA():
return globalVariableFromModuleA + '_functionA'
import moduleB
globalVariableFromModuleA = moduleB.functionB()
moduleB.py
globalVariableFromModuleB = 'globalB'
def functionB():
return 'functionB'
import moduleA
globalVariableFromModuleB = moduleA.functionA()
结果:
$ python main.py
Value=functionB_functionA
该值不包含显示其工作的"globalA",因为来自 moduleA.py 的 globalVariableFromModuleA 由 moduleB.functionB() 正确计算。
下一个示例显示,Python 不仅防止了模块导入的无休止递归,还防止了函数调用的无休止递归。 如果我们按以下方式修改 moduleB.py:
moduleB.py
globalVariableFromModuleB = 'globalB'
def functionB():
return globalVariableFromModuleB + '_functionB'
import moduleA
globalVariableFromModuleB = moduleA.functionA()
结果:
$ python main.py
Value=globalA_functionA_functionB_functionA
(在第二次进入函数A()时,它决定不再计算globalVariableFromModuleA,而是取一个初始值'globalA')