Python 设计模式,交叉导入

1 投票
3 回答
1310 浏览
提问于 2025-04-15 13:53

我正在用Python来自动化一个复杂的流程,这个流程有几个选项。我希望在Python中有以下结构:

  • 一个“流程类”,里面包含整个流程
  • 一个辅助类,里面有很多“黑盒子”(那些不常修改的函数)

99%的时间,我都是在修改流程类的内容,所以我只想在这里放一些经常需要修改的代码,这样我就不用到处滚动去找我想改的代码。这个类还包含一些全局变量(配置设置),这些变量经常会被修改。而辅助类里面的全局变量则不常被修改。

在流程类中,我有一个全局变量,我希望用户在每次运行时都必须输入。代码看起来是这样的:

print ("你想查看调试输出吗(输入 = 否)?")
debug = getUserInput()

这个getUserInput()函数应该放在辅助类中,因为它从来不需要修改。getUserInput需要一个来自流程类的全局变量,这个变量表示用户输入是否应该与Linux命令行或在Windows上运行的Eclipse保持一致。

我的问题是:我该如何最好地组织这个结构?目前的结构看起来是这样的:

import helper_class

isLinux = 1

debug = getUserInput()

辅助类:

import os, flow_class

def getUserInput():
    userInput = input ()
    if (flow_class.isLinux == 1):
        userInput = userInput[:-1]
    return userInput

现在因为交叉导入,我遇到了以下错误:

Traceback (most recent call last):
  File "flow_class.py", line 1, in <module>
    import helper_class
  File "helper_class.py", line 1, in <module>
    import os, flow_class
  File "flow_class.py", line 5, in <module>
    debug = getUserInput()
NameError: name 'getUserInput' is not defined

我知道我可以通过总是把isLinux作为参数传递给getUserInput来解决这个问题,但这样会让这个方法的使用变得复杂,也不太直观。

3 个回答

1

我想问问你最后一句话的意思。

通常来说,正如在CC2中提到的,使用全局变量在写代码的时候可能会方便,但在读代码时就不那么好理解了。
而且代码被阅读的次数远远超过写的次数;在你的情况下,我明白你是反复修改同一个脚本。

你现在遇到的问题其实就是因为选择使用全局变量这个设计决定带来的后果。
如果你能明确地传递参数,代码会更清晰,也更容易维护。

正如《Python之禅》中所说,明确总比隐含好

2

你需要在你的 flow_class 里调用 helper_class.getUserInput()。这不是关于交叉导入的问题。一旦修复了这个,你会遇到 AttributeError,这确实和交叉导入有关。

在这个阶段,你需要先实现获取 getUserInput 的逻辑,然后再导入 flow_class

关于你最后的说法,我想说的是:你的假设不正确。如果你使用明确的本地值,代码会更清晰。

1

我知道我可以通过总是把 isLinux 作为参数传给 getUserInput 来解决这个问题,但这样会让这个方法的使用变得复杂,不太直观。

其实,使用全局变量会让这个程序的使用变得比简单的参数复杂得多。

可以试试这样的做法:

debug = getUserInput(isLinux=True)

这里还有一些其他建议:

  • 你提到有很多参数会经常改变。这些参数应该硬编码在程序里吗?可以试试使用 配置文件,或者从 'flow' 传递一个字典 (dict) 作为参数。这样你就有一个集中管理的地方,可以轻松修改常用的变量,而不需要深入代码里去找!
  • 你的 'flow/helper' 类听起来像是 控制器/模型 的设计模式。这是个好主意。但你的模型不应该去导入你的控制器。

这些建议并不是特别针对“Pythonic 风格”,而是一些通用的编程实践。如果你对程序设计有疑虑,可以看看 《程序员修炼之道》,里面有很多关于工作流程和设计的好建议。还有 《代码大全》,这是 Roberto 推荐的书。

撰写回答