【问题标题】:How to fix a circular dependency for imports如何修复导入的循环依赖
【发布时间】:2010-09-17 23:05:07
【问题描述】:

我有三个文件:

测试导入模块:

#import moduleTwo
import moduleOne

hiString = "Hi!"

moduleOne.sayHi()

模块一:

import moduleTwo

class sayHi():
    moduleTwo.printHi()

模块二:

import testimports

def printHi():
    print(testimports.hiString)

如果我运行testimports,我会得到:

Traceback (most recent call last):
  File "..file path snipped../testimports/src/testimports.py", line 2, in <module>
    import moduleOne
  File "..file path snipped../testimports/src/moduleOne.py", line 1, in <module>
    import moduleTwo
  File "..file path snipped../testimports/src/moduleTwo.py", line 1, in <module>
    import testimports
  File "..file path snipped../testimports/src/testimports.py", line 6, in <module>
    moduleOne.sayHi()
AttributeError: 'module' object has no attribute 'sayHi'

但是,如果我取消注释 testimports 中的 import moduleTwo 行,程序会在停止工作之前到达这一点:

Traceback (most recent call last):
  File "..file path snipped../testimports/src/testimports.py", line 1, in <module>
    import moduleTwo
  File "..file path snipped../testimports/src/moduleTwo.py", line 1, in <module>
    import testimports
  File "..file path snipped../testimports/src/testimports.py", line 2, in <module>
    import moduleOne
  File "..file path snipped../testimports/src/moduleOne.py", line 3, in <module>
    class sayHi():
  File "..file path snipped../testimports/src/moduleOne.py", line 4, in sayHi
    moduleTwo.printHi()
AttributeError: 'module' object has no attribute 'printHi'

我将如何解决这个循环依赖问题?

【问题讨论】:

标签: python import python-3.x circular-dependency


【解决方案1】:

verisimilidude 是正确的方向。我会稍微扩展以提供更多详细信息。

在这两种情况下,都会发生以下情况:

  1. testimports 被执行为 __main__
  2. testimports 导入 moduleOne。现在 moduleOne 从文件中读取并添加到导入模块列表 sys.modules
  3. 导入moduleOne 的执行从导入moduleTwo 开始。现在moduleTwo 从文件中读取并添加到导入模块列表sys.modules。请注意,在此阶段,moduleOne 的其余部分尚未执行,因此未定义 sayHi
  4. 现在moduleTwo 通过导入testimports 开始执行。这是第一次导入testimports,它与__main__ 相同无关。它现在被插入到sys.modules
  5. 这就是事情变得有趣的地方。新导入的testimports 导入moduleOnemoduleOne 已经在sys.modules,所以不会再次读取。然后执行进行到moduleOne.sayHi() 行。 moduleOne 的导入尚未完成,sayHi 尚未定义。因此我们得到了错误。

如果取消注释moduleTwo,则会发生类似的循环。本质上,__main__ 导入 moduleTwotestimports 通过导入已经导入的moduleTwo,导入moduleOne;依次导入moduleTwo,然后尝试调用尚未定义的moduleTwo.printHi,因为moduleTwo一直没有完成执行。

Anatoly Rr 的解决方案通过使模块testimports 在导入时不调用任何其他模块功能来打破这一切。所以当它被moduleTwo 导入时,它不会调用moduleOne.sayHi。只有以__main__ 启动时才会执行,以便在所有导入后延迟执行。

故事的寓意? Avoid circular dependencies in Python if possible.

【讨论】:

    【解决方案2】:

    重写testimports.py 可能会有所帮助:

    import moduleOne
    
    hiString = "Hi!"
    
    def main ():
        moduleOne.sayHi()
    
    if __name__ == "__main__":
        main ()
    

    【讨论】:

      【解决方案3】:

      您的问题是,当 Python 导入某些内容时,它会在基本级别执行所有语句。当 Module3 将原始 testimports.py 作为模块导入时,再次分配 hiString 并再次进行调用。 Anatoly Rr 的解决方案有效,因为调用现在位于 def 中。未调用 def 是因为 __name__ 向 Python 运行时指示正在导入模块。从命令行调用它时,它的模块名称将是__main__

      【讨论】:

      • 实际上并不准确。例如,没有再次分配hiString,但会有两个hiString。在这两种情况下,除了导入的 testimports 之外,还会有一个 __main__ 。详情见我的回答。
      猜你喜欢
      • 2019-11-01
      • 1970-01-01
      • 2019-12-03
      • 2010-12-06
      • 2016-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多