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

Геттер с побочным эффектом

Я создаю класс, объекты которого инициализируются куча XML-кода. Класс имеет возможность извлекать различные параметры из этого XML и кэшировать их внутри переменных состояния объекта. Потенциальная величина этих параметров велика и, скорее всего, пользователю не понадобится большинство из них. Вот почему я решил выполнить "ленивую" инициализацию.

В следующем тестовом примере такой параметр title. Когда пользователь пытается получить доступ к нему в первый раз, функция getter анализирует XML, правильно инициализирует переменную состояния и возвращает ее значение:

class MyClass(object):     
    def __init__(self, xml=None):
        self.xml  = xml
        self.title = None

    def get_title(self):
        if self.__title is None:
            self.__title = self.__title_from_xml()
        return self.__title

    def set_title(self, value):
        self.__title = value

    title = property(get_title, set_title, None, "Citation title")

    def __title_from_xml(self):
        #parse the XML and return the title
        return title         

Это выглядит хорошо и отлично работает для меня. Однако меня немного беспокоит тот факт, что функция геттера фактически является "сеттерной" в том смысле, что она оказывает очень существенное побочное воздействие на объект. Является ли это законной проблемой? Если да, то как мне его адресовать?

4b9b3361

Ответ 1

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

Ответ 2

Этот шаблон дизайна называется Lazy initialization и имеет законное использование.

Ответ 3

Несколько лет спустя, но хорошо: в то время как ленивая инициализация в порядке сама по себе, я бы определенно не откладывал разбор xml и т.д., пока кто-то не обратится к объекту title. Вычисляемые атрибуты должны вести себя как простые атрибуты, а простой доступ к атрибутам никогда не будет повышаться (при условии, что атрибут существует, конечно).

FWIW У меня был очень похожий случай в каком-то проекте, который я взял на себя, с ошибками разбора xml, происходящими в самых неожиданных местах, из-за того, что предыдущий разработчик использовал свойства так же, как и в примере OP, и ему пришлось исправить это путем размещения парсинга и валидации в момент инициализации.

Итак, используйте свойства для ленивой инициализации только тогда, когда и когда вы знаете, что первый доступ никогда не будет повышаться. Собственно, никогда не используйте свойство для чего-либо, что может поднять (по крайней мере, когда настройка получения - это другая ситуация). Else, не используйте свойство, сделайте getter явным методом и четко документируйте, что он может поднять то или это.

NB: использование свойства для кеширования не является проблемой здесь, это само по себе прекрасно.