python 循环导入的解决方法

python workaround for circular import

好的,就是这样。

我宁愿不放弃我的代码,但如果你真的需要它,我会的。我有两个模块彼此需要一点。这些模块称为 webhandler 和 datahandler。

在 webhandler 中我有一行:

import datahandler 

在数据处理程序中我还有另一行:

import webhandler

现在我知道这是糟糕的代码,像这样的循环导入会导致代码 运行 两次(这是我试图避免的)。

然而,datahandler 模块需要访问 webhandler 模块的几个函数,webhandler 模块需要访问在 datahandler 模块中生成的几个变量。除了将函数移动到不同的模块之外,我没有看到任何解决方法,但这会破坏我的程序的组织并且对模块命名没有逻辑意义。

有什么帮助吗?

the webhandler module needs access to several variables that are generated in the datahandler module

将任何 "generated" 数据推送到第三个位置可能是有意义的。所以 datahandler 函数在适当的时候调用 config.setvar( name, value ),而 webhandler 函数在需要的时候调用 config.getvar( name )config 将是第三个子模块,包含您编写的简单 setvargetvar 函数(围绕全局字典的 setting/getting 元素进行包装将是最简单的方法)。

那么 datahandler 代码会 import webhandler, configwebhandler 只需要 import config.

我同意 poke 但是,提出这样一个问题的必要性暴露了一个事实,即您可能 还没有 将设计完成得既整齐又合乎逻辑如你所想。如果是我,我会重新考虑模块的划分方式

循环依赖是一种代码异味。如果你有两个相互依赖的模块,那么这是一个非常糟糕的迹象,你应该重构你的代码。

有几种不同的方法可以做到这一点;哪个最好取决于你在做什么,以及每个模块的哪些部分实际上被另一个模块使用。

  • 一个非常简单的解决方案是合并两个模块,这样您就只有一个模块,它只依赖于自身,或者更确切地说,依赖于它自己的内容。这很简单,但是由于您之前已经分离了模块,因此您可能会以这种方式引入新问题,因为您不再有关注点分离。
  • 另一个解决方案是确保确实需要依赖项。如果一个模块只有几个部分依赖于另一个,也许你可以以不再需要循环依赖的方式移动这些位,或者 utilize the way imports work 使循环依赖不再是一个问题.
  • 更好的解决方案可能是将依赖项移动到一个单独的新模块中。如果命名真的是最难的问题,那么你可能做对了。它可能 “破坏 [你的] 程序的组织” 但是由于你有循环依赖,无论如何你的设置存在一些固有的错误。

其他人所说的不进行循环导入是最好的解决方案,但如果您最终绝对需要它们(可能是为了向后兼容或代码清晰),它通常只在其中一个方法或函数中模块。因此你可以安全地这样做:

# modA.py
import modB

# modB.py
def functionDependingOnA():
    import modA
    ...

每次调用该函数时执行导入都会产生轻微的开销,但除非一直调用,否则开销相当低。 (在我的测试中大约 400ns)。

您也可以这样做,甚至可以避免查找:

# modA -- same as above.

# modB.py
_imports = {}

def _importA():
    import modA
    _imports['modA'] = modA
    return modA

def functionDependingOnA():
    modA = _imports.get('modA') or _importA()

此版本仅在第二次和后续调用上增加了 40ns 的时间,或与空本地函数调用的时间大致相同。

SqlAlchemy 使用依赖注入模式,其中所需的模块由装饰器传递给函数:

@util.dependencies("sqlalchemy.orm.util")
def identity_key(cls, orm_util, *args, **kwargs):
    return orm_util.identity_key(*args, **kwargs)

这种方法与在函数中执行 import 基本相同,但性能稍好。