Python中的循环导入使得无法从上层模块调用函数

时间:2017-05-18 13:45:15

标签: python import module cyclic

以下是我的代码。

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:在我的情况下,moduleB显式导入moduleA,因此我希望它可以工作,但事实并非如此。这是因为Python实现了进口并且没有两次进行吗?但是为什么它不能从内存中取出已经兑现的moduleA.functionA()而不是失败?我想当前的行为是一个错误。

Q2:如果我删除行“globalVariableFromModuleB = moduleA.functionA()”并只保留循环导入“import moduleA”,那么我没有失败。因此,Python中不禁止循环依赖。如果它们不能正常工作,那么它们允许的是什么,因为它显示了我的例子?

问题3:如果我将“import moduleA”更改为“from moduleA import functionA”,则主程序无法使用另一条消息“ImportError:无法导入名称functionA”失败。

另外,我想在这里发布针对那些不喜欢重新设计应用程序的人的解决方法,就像我的情况一样。
解决方法(仅通过实验找到)。要在main.py中的“import moduleA”之前添加“import moduleB”,即:

# main.py
import moduleB
import moduleA
print('It works!')

但是我必须在代码中的这个导入处留下长篇评论,因为main.py不直接使用来自moduleB的任何API,所以它看起来很难看。

有人可以建议一些更好的解决这种情况并回答上述3个问题吗?

2 个答案:

答案 0 :(得分:2)

在python中循环导入是一个非常讨厌的“Gotcha”; this文章很好地解释了所有内容 - 请仔细阅读。

要解决这个问题,您只需要制动循环 - 在您的情况下,您可以放弃模块B中的导入ModuleA ,因为它不需要(您已经在主要导入A)

要真正了解正在发生的事情,请考虑以下事项:

  • 你做导入,python会加载代码 并逐行执行它并将其添加到sys.modules中 知道它已经导入了

  • 如果导入包含另一个import语句,python将加载并开始执行该代码,然后将模块名称添加到sys.module

  • 在您的情况下,sys.modules包含moduleA和moduleB,但由于模块A的执行被 import moduleB 语句“中断”,因此函数定义永远不会被执行,但是模块点已添加到sys.modules =&gt; AttributeError:'module'对象没有属性'functionA'

希望这有帮助。

答案 1 :(得分:0)

例如,我会在这里发布更复杂的案例(当每个模块从全局上下文中的另一个模块调用一个函数时),该函数无需重新设计程序:

main.py

within

moduleA.py

import moduleA
print('Value=%s' % moduleA.functionA())

moduleB.py

globalVariableFromModuleA = 'globalA'
def functionA():
    return globalVariableFromModuleA + '_functionA'

import moduleB
globalVariableFromModuleA = moduleB.functionB()

结果:

globalVariableFromModuleB = 'globalB'
def functionB():
    return 'functionB'

import moduleA
globalVariableFromModuleB = moduleA.functionA()

该值不包含&#39; globalA&#39;这表明它有效,因为来自moduleA.py的globalVariableFromModuleA被moduleB.functionB()正确评估。

下一个例子表明,Python不仅可以导入模块,还可以防止无限递归,也可以用于函数调用。 如果我们通过以下方式修改moduleB.py:

moduleB.py

$ python main.py 
Value=functionB_functionA

结果:

globalVariableFromModuleB = 'globalB'
def functionB():
    return globalVariableFromModuleB + '_functionB'

import moduleA
globalVariableFromModuleB = moduleA.functionA()

(在第二次进入functionA()时,它决定不再评估globalVariableFromModuleA,而是采用初始值&#39; globalA&#39;)