Python: идиоматические свойства структурированных данных?

У меня неприятный запах в моем коде. Возможно, мне просто нужно дать ему немного проветриться, но прямо сейчас

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

Я хотел бы сохранить входные параметры как общий объект Python, который я могу передать трем другим функциям, каждая из которых будет переводить этот общий объект в конкретные параметры, необходимые для запуска программного обеспечения RTM, которым они являются. Ответственность. Я думаю, что это имеет смысл, но не стесняйтесь критиковать мой подход.

Существует много возможных входных параметров для каждой части программного обеспечения RTM. Многие из них перекрываются.

Я начал с простого словаря

config = {
    day_of_year: 138,
    time_of_day: 36000, #seconds
    solar_azimuth_angle: 73, #degrees
    solar_zenith_angle: 17, #degrees
    ...
}

. есть много параметров, и их можно четко разделить на группы, поэтому я подумал об использовании dictвнутри dict:

config = {
    day_of_year: 138,
    time_of_day: 36000, #seconds
    solar: {
        azimuth_angle: 73, #degrees
        zenith_angle: 17, #degrees
        ...
    },
    ...
}

Мне это нравится. Но есть много лишних свойств. Солнечный азимут и зенитный угол, например, могут быть найдены, если известен другой, так зачем жестко кодировать оба? Итак, я начал изучать встроенное свойство Python.Это позволяет мне делать отличные вещи с данными, если я сохраняю их как атрибуты объекта:

class Configuration(object):
    day_of_year = 138,
    time_of_day = 36000, #seconds
    solar_azimuth_angle = 73, #degrees
    @property
    def solar_zenith_angle(self):
        return 90 - self.solar_azimuth_angle
    ...

config = Configuration()

Но теперь я потерял структуру, которая была у меня во втором dictпримере.

Обратите внимание, что некоторые свойства менее тривиальны, чем мой пример solar_zenith_angle, и могут потребовать доступа к другим атрибутам за пределами группы атрибутов, частью которой они являются. Например, я могу вычислить солнечный_азимут_угол, если знаю день года, время суток, широту и долготу.

Что мне нужно:

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

Несколько скучная возможность:

Хранить все в словаре словарей, о котором я говорил ранее, и заставлять другие функции работать с объектом и вычислять вычисляемые значения? Это не звучит весело. Или чистый. Для меня это звучит грязно и неприятно.

Уродливое, но работающее:

После долгого времени, пробуя разные стратегии и в основном ничего не получая, я придумал одно возможное решение, которое, кажется, работает:

Мои классы:(немного пахнет func-y, er, funky. Определенно.)

class SubConfig(object):
    """
    Store logical groupings of object attributes and properties.

    The parent object must be passed to the constructor so that we can still
    access the parent object's other attributes and properties. Useful if we
    want to use them to compute a property in here.
    """
    def __init__(self, parent, *args, **kwargs):
        super(SubConfig, self).__init__(*args, **kwargs)
        self.parent = parent


class Configuration(object):
    """
    Some object which holds many attributes and properties.

    Related configurations settings are grouped in SubConfig objects.
    """
    def __init__(self, *args, **kwargs):
        super(Configuration, self).__init__(*args, **kwargs)
        self.root_config = 2

        class _AConfigGroup(SubConfig):
            sub_config = 3
            @property
            def sub_property(self):
                return self.sub_config * self.parent.root_config
        self.group = _AConfigGroup(self) # Stinky?!

Как я могу их использовать: (работает так, как я хотел бы)

config = Configuration()

# Inspect the state of the attributes and properties.
print("\nInitial configuration state:")
print("config.rootconfig: %s" % config.root_config)
print("config.group.sub_config: %s" % config.group.sub_config)
print("config.group.sub_property: %s (calculated)" % config.group.sub_property)

# Inspect whether the properties compute the correct value after we alter
# some attributes.
config.root_config = 4
config.group.sub_config = 5

print("\nState after modifications:")
print("config.rootconfig: %s" % config.root_config)
print("config.group.sub_config: %s" % config.group.sub_config)
print("config.group.sub_property: %s (calculated)" % config.group.sub_property)

Поведение: (вывод выполнения всего вышеперечисленного код, как и ожидалось)

Initial configuration state:
config.rootconfig: 2
config.group.sub_config: 3
config.group.sub_property: 6 (calculated)

State after modifications:
config.rootconfig: 4
config.group.sub_config: 5
config.group.sub_property: 20 (calculated)

Почему мне это не нравится:

Хранение данных конфигурации в определениях классов внутри основного объекта __init__()не кажется элегантным.Особенно необходимость создавать их экземпляры сразу после такого определения. Фу. Конечно, я могу справиться с этим для родительского класса, но делать это в конструкторе...

Хранение одних и тех же классов вне основного объекта Configurationтакже не кажется элегантным, поскольку свойства в внутренние классы могут зависеть от атрибутов Configuration(или их братьев и сестер внутри него).

Я мог бы иметь дело с определением функций вне всего, поэтому внутри имел бы такие вещи, как

@property
def solar_zenith_angle(self):
   return calculate_zenith(self.solar_azimuth_angle)

, но я не могу понять, как сделать что-то вроде

@property
def solar.zenith_angle(self):
    return calculate_zenith(self.solar.azimuth_angle)

(когда я пытаюсь быть умным в этом, я всегда сталкиваюсь с )

Итак, как правильно поступить в этом случае? Я упускаю что-то основное или использую очень неправильный подход? Кто-нибудь знает умное решение?

Помогите! Мой код Python некрасивый! Должно быть, я делаю что-то не так!

7
задан Phil 24 May 2012 в 23:40
поделиться