【问题标题】:Circular imports Python循环导入 Python
【发布时间】:2023-07-28 09:15:01
【问题描述】:

我已阅读 this post 关于 Python 循环导入的内容。它描述了以下场景,并认为这会在运行时引发错误:

# module1
import module2

def function1():
    module2.function2()

def function3():
    print('Goodbye, World!')
# module2
import module1

def function2():
    print('Hello, World!')
    module1.function3()
# __init__.py
import module1

module1.function1()

但是当我运行它(Python 3.95)时,它运行得非常好。这篇文章很旧,它没有指定它使用的 Python 版本。也许支持这一点的后来的 Python 有一些变化?

【问题讨论】:

  • 这可能是一个愚蠢的问题,但是您在此处粘贴的代码是在不同的模块中吗?还是只是一个带有 cmets 的文件?
  • 这些是不同的模块
  • 我在 python 3.5.2 上试过,它也可以在那里工作
  • 这篇文章来自 2017 年,显然使用 __init__ 中的任何内容之前始终加载这两个模块。
  • 我可能是错的,但我认为循环导入是使用相对导入时的问题。如果您使用绝对导入,那么您的代码可以工作(或至少应该)。看看this link

标签: python circular-dependency


【解决方案1】:

以下是 Python 3 代码中发生的事件的简化序列:

  1. __init__.py 开始运行
  2. import module1 开始加载 module1.py
    • 一个空的module1 模块被添加到sys.modules
  3. import module2 开始加载 module2.py
    • 一个空的module2 模块被添加到sys.modules
  4. module2.function2 被创建并添加到 module2.__dict__
    • function2 引用 module1 中的名称这一事实不会以任何方式影响函数对象的创建
  5. module2 已完全加载,执行返回到 module1
  6. module1.function1module1.function3 被创建并添加到 module1.__dict__
    • 同样,函数引用的名称并不重要,因为它们没有被调用。如有必要,AttributeErrorNameError 可以在运行时引发。
  7. module1 已完全加载,执行返回到 __main__
  8. module1.function 运行成功,因为它引用的所有名称都是可解析的。

如您所见,在这个特定的导入序列中没有循环导入问题,因为module1module2 不会尝试调用彼此的函数。当前的导入系统允许在调用函数之前加载两个模块。

您提到的帖子是2017年的,并且必须使用3.0之前的python版本。在以下引用的链接中可以找到提示,该引用链接到 python-2.x 文档:

这种方法与 Python 语法并不矛盾,正如 Python documentation says:“习惯上但不需要将所有 import 语句放在模块(或脚本,就此而言)的开头”。

顺便说一句,后面的段落有点误导:

Python 文档还说建议使用import X,而不是其他语句,例如from module import *from module import a,b,c

虽然不鼓励使用星号导入,但通常非常鼓励使用 from module import a,b,c 形式的特定名称导入,只有少数例外。

【讨论】: