Подтвердить что ты не робот

Как разработать программу со многими параметрами конфигурации?

Предположим, у меня есть программа с большим количеством параметров конфигурации. Пользователь может указать их в файле конфигурации. Моя программа может анализировать этот файл конфигурации, но как его внутренне хранить и передавать параметры?

В моем случае программное обеспечение используется для проведения научного моделирования. Есть около 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, но мой вопрос означает любое подобное программирование langauge.

4b9b3361

Ответ 1

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']

Ответ 2

Несколько шаблонов проектирования помогут

  • Прототип
  • Factory и Аннотация Factory

Используйте эти два шаблона с объектами конфигурации. Затем каждый метод принимает объект конфигурации и использует то, что ему нужно. Также рассмотрите возможность применения логической группировки к параметрам конфигурации и подумайте о способах сокращения количества входов.

psuedo code

// 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() );

Внутри каждого метода factory он может создать конфигурацию из объекта-прототипа (который имеет все значения "по умолчанию" ), а файл параметров становится только тем, что отличается от значения по умолчанию. Это будет сопряжено с четкой документацией о том, что это за значения по умолчанию, и когда человек (или другая программа) может захотеть их изменить.

** Изменить: ** Также учтите, что каждая конфигурация, возвращаемая factory, является подмножеством общей конфигурации.

Ответ 3

Пропустите либо класс разбора конфигурации, либо напишите класс, который его обертывает и разумно вытаскивает запрошенные параметры.

Стандартная библиотека Python configparser раскрывает разделы и параметры файла конфигурации стиля INI с использованием протокола сопоставления, и поэтому вы можете варианты непосредственно из этого, как если бы это был словарь.

myconf = configparser.ConfigParser()
myconf.read('myconf.ini')
what_to_do = myconf['section']['option']

Если вы явно хотите предоставить параметры с использованием нотации атрибутов, создайте класс, который переопределяет __getattr__:

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

Ответ 4

Имейте модуль загружать params в его пространство имен, затем импортировать его и использовать там, где вы хотите.
Также см. Соответствующий вопрос здесь