Как привязать данные экземпляра объекта A к соответствующему экземпляру объекта B? - PullRequest
1 голос
/ 27 марта 2019

Я пишу еще один «велосипед» для чтения файлов .ini, чтобы получить опыт работы с продвинутыми Python и ООП. Также я нахожу стиль доступа Python для configparser по умолчанию немного неприятным для глаз, то есть: something = config['section']['parameter'] вместо большего количества очарования something = config.section.parameter.

Я закончил с этим дизайном:

  • ConfigStorage объект для хранения пар параметр / значение в качестве словаря;
  • Config объект для управления данными в объекте хранения.

__getattribute__ в Config объект переопределен, поэтому я могу получить доступ к значениям в ConfigStorage словаре по имени атрибута Config объекта ( цель! ).

Система работает нормально, когда существует только один экземпляр объекта Config. Когда я попытался работать с несколькими конфигами (и, следовательно, создать новые Config объекты для управления ими), я понял, что ConfigStorage - это один для всех .

Я пытался создать новый экземпляр ConfigStorage для каждого Config объекта, но Python достигает максимальной глубины рекурсии в этом коде ( почему? ):

class _ConfigStorage(object):
    def __init__(self):
        self.config = dict()


class Config(object):
    def __getattribute__(self, name):
        if name in self.c.config:
            return self.c.config[name]
        else:
            raise AttributeError("No parameter named [%s]" % name)

    def __init__(self, file):
        self.c = _ConfigStorage()
        with open(file, 'r') as f:
            for config_line in f:
                key = # getting key from line
                value = # getting value
                self.c.config[key] = value

Наконец, мой код заработал, но я нахожу это решение очень грубым и испорченным черной магией. Я разделяю данные в объекте хранения, добавляя к ключу словаря строковое представление Config ID объекта. Объект ConfigStorage все еще один.
Также необходим метод __del__, так как GC не знает о ненужных данных в хранилище, и я должен удалить их вручную. Это отстой.

class _ConfigStorage(object):
    config = dict()


class Config(object):
    def __getattribute__(self, name):
        key = str(id(self)) + name
        if key in _ConfigStorage.config:
            return _ConfigStorage.config[key]
        else:
            raise AttributeError("No parameter named [%s]" % name)

    def __init__(self, file):
        with open(file, 'r') as f:
            for config_line in f:
                key = str(id(self) + # getting key from line
                value = # getting value
                _ConfigStorage.config[key] = value

    def __del__(self):
        instance_id = str(id(self))
        keys_to_delete = []
        for key in _ConfigStorage.config:
            if instance_id in key:
                keys_to_delete.append(key)
        for key_to_delete in keys_to_delete:
            del _ConfigStorage.config[key_to_delete]

Как улучшить дизайн, получив доступ к данным словаря по атрибуту объекта?

Ответы [ 2 ]

1 голос
/ 27 марта 2019

Я думаю, что эта реализация соответствует вашим потребностям:

class Config(object):
    def __getattr__(self, name):
        if name in self.config:
            return self.config[name]
        else:
            raise AttributeError("No parameter named [%s]" % name)

    def __init__(self, file=None):
        # changed to make it work without real file
        self.config = {'key': 'value'}

config = Config()
print(config.key)  # value
print(config.not_a_key)  # AttributeError: ...

Нет необходимости писать _ConfigStorage и __del__, нет бесконечной рекурсии, доступ по точечной нотации.

0 голосов
/ 27 марта 2019

Глупо, но я нашел более изящный способ решения своей проблемы.

class Config(object):
    config = dict()

    def __getattribute__(self, name):
        if name in Config.config:
            return Config.config[name]
        else:
            raise AttributeError("No parameter named [%s]" % name)

    def __init__(self, file):
        try:
            with open(file, 'r') as f:
                for config_line in f:
                    config_line = config_line.strip()
                    eq_position = config_line.find('=')
                    key = config_line[:eq_position].strip()
                    value = config_line[eq_position + 1:].strip()
                    Config.config[key] = value
        except FileNotFoundError:
            print('File not found')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...