8

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

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

问题:

logging模块需要该configuration模块的一些配置数据。但是,对于某些configuration功能,我真的很想使用logging模块中定义的自定义日志记录功能。显然,将logging模块导入configuration会引发错误。

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

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

  2. 猴子补丁模块。这听起来还不错:在初始导入之后和实际使用它的任何功能之前logging动态加载模块。不过,这意味着定义全局的、每个模块的变量。configuration

  3. 依赖注入。我已经阅读并遇到了依赖注入替代方案(特别是在 Java Enterprise 领域),它们消除了一些令人头疼的问题;但是,它们可能过于复杂而无法使用和管理,这是我们想要避免的。不过,我不知道全景图在 Python 中是如何描述的。

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

非常感谢!

4

4 回答 4

4

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

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

如果没有内部知识,并且仅使用常识,“配置”模块应该是简单的东西,不需要太多处理,它应该是导入树中的一个叶子。

希望能帮助到你!

于 2013-12-04T23:05:16.543 回答
3

这对你有用吗?

# 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 中的 import b 语句引起)抛出异常时,它会被捕获并丢弃。当然,您的整个模块 b 必须缩进一个额外的块间距,并且您必须了解变量 HELLO 在 a 中的声明位置。

如果您不想通过插入 try:except: 逻辑来修改 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,并覆盖循环导入。

我知道这很恶心,所以不要告诉任何人。

于 2013-12-04T21:57:45.727 回答
2

因此,如果我正确阅读了您的用例,请logging访问configuration以获取配置数据。但是,configuration有一些函数在调用时需要loggingconfiguration.

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

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

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

于 2013-12-05T01:24:09.763 回答
2

循环模块依赖通常是代码异味。

它表示应该重构部分代码,使其在两个模块之外。

于 2013-12-04T20:01:53.490 回答