如何正确处理Python中的循环模块依赖关系



试图找到一个好的、合适的模式来处理Python中的循环模块依赖关系。通常,解决方案是删除它(通过重构);然而,在这种特殊情况下,我们确实希望拥有需要循环导入的功能。

EDIT:根据下面的答案,这类问题的通常攻击角度是重构。然而,为了这个问题,假设这不是一个选择(无论出于何种原因)。

问题:

logging模块要求configuration模块提供一些配置数据。但是,对于某些configuration函数,我确实希望使用logging模块中定义的自定义日志记录函数。显然,在configuration中导入logging模块会引发错误。

我们可以想到的可能解决方案:

  1. 不要这样做。正如我之前所说,这不是一个好的选择,除非所有其他可能性都是丑陋和糟糕的。

  2. Monkey修补模块。这听起来还不错:在初始导入之后,在实际使用其任何函数之前,将logging模块动态加载到configuration中。这意味着定义全局的、每个模块的变量。

  3. 依赖项注入。我读过并遇到过依赖注入替代方案(特别是在Java企业领域),它们消除了一些令人头疼的问题;然而,它们可能过于复杂,无法使用和管理,这是我们希望避免的。不过,我不知道Python中的全景图是怎么回事。

启用此功能的好方法是什么?

非常感谢!

如前所述,可能需要进行一些重构。根据名称,如果日志记录模块使用配置可能没问题,当考虑配置中应该有什么时,考虑配置参数,那么就会出现一个问题,为什么要进行配置日志记录?

配置中使用日志记录的代码部分可能不属于配置模块:它似乎正在进行某种处理并记录结果或错误。

如果没有内部知识,只使用常识,"配置"模块应该是简单的,不需要太多处理,它应该是导入树中的一片叶子。

希望它能有所帮助!

这对你有用吗?

# MODULE a (file a.py)
import b
HELLO = "Hello"
# MODULE b (file b.py)
try:
    import a
    # All the code for b goes here, for example:
    print("b done",a.HELLO))
except:
    if hasattr(a,'HELLO'):
        raise
    else:
        pass

现在我可以执行导入b。当循环导入(由a中的导入b语句引起)抛出异常时,它会被捕获并丢弃。当然,您的整个模块b将不得不缩进一个额外的块间距,并且您必须了解变量HELLO在a中声明的位置。

如果你不想通过插入try:axcept:logic来修改b.py,你可以将整个b源移到一个新文件中,称之为c.py,并制作一个简单的文件b.py,如下所示:

# new Module b.py
try:
    from c import *
    print("b done",a.HELLO) 
except:
    if hasattr(a,"HELLO"):
        raise
    else:
        pass
# The c.py file is now a copy of b.py:
import a
# All the code from the original b, for example:
print("b done",a.HELLO))

这将把整个命名空间从c导入到b,并覆盖循环导入。

我意识到这很恶心,所以不要告诉任何人。

循环模块依赖关系通常是一种代码气味。

它指示代码的一部分应该被重新分解,以便它在两个模块之外。

因此,如果我正确阅读了您的用例,logging将访问configuration以获取配置数据。然而,configuration有一些函数,当被调用时,需要将logging中的内容导入configuration

如果是这种情况(也就是说,在开始调用函数之前,configuration并不真正需要logging),答案很简单:在configuration中,将所有从logging导入的内容放在文件的底部,在所有类、函数和常量定义之后。

Python从上到下读取内容:当它在configuration中遇到import语句时,它会运行它,但此时configuration已经作为一个可以导入的模块存在,即使它还没有完全初始化:它只具有在import语句运行之前声明的属性。

不过,我确实同意其他人的观点,即循环导入通常是一种代码气味。

相关内容

  • 没有找到相关文章

最新更新