1

下面是我的代码。

主要.py:

import moduleA
print('It works!')

模块A.py:

import moduleB
def functionA():
    return 0

模块B.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 中是不被禁止的。如果他们不正确地工作,因为它显示了我的例子,他们被允许做什么?

Q3:如果我将“import moduleA”更改为“from moduleA import functionA”,主程序将无法运行,并出现另一条消息“ImportError: cannot import name functionA”。

此外,我想在这里为那些不喜欢重新设计应用程序的人发布一个解决方法,比如我的情况。
解决方法(只是通过实验发现)。在main.py中的“import moduleA”之前添加“import moduleB” ,即:

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

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

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

4

2 回答 2

2

python中的循环导入是一个非常讨厌的“陷阱”;这篇文章很好地解释了所有的细节 - 请仔细阅读它。

要解决这个问题,您只需停止循环 - 在您的情况下,您可以将 import ModuleA放在 moduleB 中,因为它不需要(您已经在 main 中导入了 A)

要真正了解发生了什么,请考虑以下几点:

  • 你确实 import ,python 将加载代码并逐行执行它并将它添加到 sys.modules 以便它知道它已经被导入

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

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

希望这可以帮助。

于 2017-05-18T14:56:15.550 回答
0

例如,我会在这里发布更复杂的情况(当每个模块在全局上下文中从另一个模块调用一个函数时),无需对程序进行重大重新设计即可工作:

主文件

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

模块A.py

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

import moduleB
globalVariableFromModuleA = moduleB.functionB()

模块B.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 如下方式:

模块B.py

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

import moduleA
globalVariableFromModuleB = moduleA.functionA()

结果:

$ python main.py 
Value=globalA_functionA_functionB_functionA

(在第二次进入 functionA() 时,它决定不再评估 globalVariableFromModuleA,而是取一个初始值'globalA')

于 2017-05-24T14:29:35.740 回答