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
将是第三个子模块,包含您编写的简单 setvar
和 getvar
函数(围绕全局字典的 setting/getting 元素进行包装将是最简单的方法)。
那么 datahandler
代码会 import webhandler, config
但 webhandler
只需要 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
基本相同,但性能稍好。
好的,就是这样。
我宁愿不放弃我的代码,但如果你真的需要它,我会的。我有两个模块彼此需要一点。这些模块称为 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
将是第三个子模块,包含您编写的简单 setvar
和 getvar
函数(围绕全局字典的 setting/getting 元素进行包装将是最简单的方法)。
那么 datahandler
代码会 import webhandler, config
但 webhandler
只需要 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
基本相同,但性能稍好。