Python 如何设计具有许多配置选项的程序?

Python 如何设计具有许多配置选项的程序?,python,api,coding-style,Python,Api,Coding Style,假设我有一个有大量配置选项的程序。用户可以在配置文件中指定它们。我的程序可以解析这个配置文件,但是它应该如何在内部存储和传递选项呢 在我的例子中,该软件用于执行科学模拟。大约有200个选项,其中大多数都有正常的默认值。通常,用户只需指定一打左右。我面临的困难是如何设计我的内部代码。许多需要构造的对象依赖于许多配置选项。例如,一个对象可能需要几个路径(用于存储数据的位置)、一些需要传递给该对象将调用的算法的选项,以及一些由该对象本身直接使用的选项 这导致需要构造大量参数的对象。此外,由于我的代码库

假设我有一个有大量配置选项的程序。用户可以在配置文件中指定它们。我的程序可以解析这个配置文件,但是它应该如何在内部存储和传递选项呢

在我的例子中,该软件用于执行科学模拟。大约有200个选项,其中大多数都有正常的默认值。通常,用户只需指定一打左右。我面临的困难是如何设计我的内部代码。许多需要构造的对象依赖于许多配置选项。例如,一个对象可能需要几个路径(用于存储数据的位置)、一些需要传递给该对象将调用的算法的选项,以及一些由该对象本身直接使用的选项

这导致需要构造大量参数的对象。此外,由于我的代码库正在进行非常积极的开发,因此要遍历调用堆栈并将新的配置选项一直传递到需要它的地方是一件非常痛苦的事情

防止这种痛苦的一种方法是拥有一个可以在代码中任意位置自由使用的全局配置对象。我并不特别喜欢这种方法,因为它会导致函数和类不接受任何(或只接受一个)参数,而且读者也不清楚函数/类处理的是什么数据。它还防止了代码重用,因为所有代码都依赖于一个巨大的配置对象

有谁能给我一些关于这样一个程序应该如何构造的建议吗

下面是我对配置选项传递样式的一个示例:

class A:
    def __init__(self, opt_a, opt_b,  ..., opt_z):
        self.opt_a = opt_a
        self.opt_b = opt_b
        ...
        self.opt_z = opt_z

    def foo(self, arg):
        algo(arg, opt_a, opt_e)
以下是全局配置样式的示例:

class A:
    def __init__(self, config):
        self.config = config

    def foo(self, arg):
        algo(arg, config)

这些例子是用Python编写的,但我的问题代表任何类似的编程语言。

一些设计模式会有所帮助

  • 原型
  • 工厂与抽象工厂
将这两种模式用于配置对象。然后,每个方法将获取一个配置对象并使用它所需的内容。还考虑应用逻辑分组来配置参数,并考虑减少输入数量的方法。

伪代码

// Consider we  can run three different kinds of Simulations. sim1, sim2, sim3

ConfigFactory configFactory = new ConfigFactory("/path/to/option/file");
....
Simulation1 sim1;
Simulation2 sim2;
Simulation3 sim3;

sim1.run( configFactory.ConfigForSim1() );
sim2.run( configFactory.ConfigForSim2() );
sim3.run( configFactory.ConfigForSim3() );
在每个工厂方法内部,它可能会从原型对象(具有所有“正常”默认值)创建一个配置,选项文件会变成与默认值不同的东西。这将与关于这些默认值是什么以及个人(或其他程序)何时可能想要更改它们的清晰文档相结合

**编辑:**
还可以考虑,工厂返回的每个配置是整个配置的子集。

传递配置配置类,或者编写一个封装它的类,并智能地取出所请求的选项。 Python的标准库使用映射协议公开INI样式配置文件的部分和选项,因此您可以直接从中检索选项,就像它是一个字典一样

myconf = configparser.ConfigParser()
myconf.read('myconf.ini')
what_to_do = myconf['section']['option']
如果明确希望使用属性表示法提供选项,请创建一个覆盖
\uuu getattr\uuu
的类:

class MyConf:
    def __init__(self, path):
        self._parser = configparser.ConfigParser()
        self._parser.read('myconf.ini')
    def __getattr__(self, option):
        return self._parser[{'what_to_do': 'section'}[option]][option]

myconf = MyConf()
what_to_do = myconf.what_to_do

matplotlib是一个具有许多配置选项的大型软件包。它使用rcParams模块来管理所有默认参数。rcParams将所有默认参数保存在dict中

每个函数都将从关键字参数中获取选项:

例如:

def f(x,y,opt_a=None, opt_b=None):
    if opt_a is None: opt_a = rcParams['group1.opt_a']

让模块将参数加载到其名称空间,然后导入它并在任何地方使用。

另请参见相关问题

全局配置对象将所有代码耦合在一起。这将是很好的,有更多的程序模块化。我喜欢@HYRY显示的解决方案。这似乎是两全其美。