Лучшая практика при определении переменных экземпляра

Я новичок в Python и задаю вопрос относительно следующего класса:

class Configuration:
    def __init__(self):
        parser = SafeConfigParser()
        try:
            if parser.read(CONFIG_FILE) is None:
                raise IOError('Cannot open configuration file')
        except IOError, error:
            sys.exit(error)
        else:
            self.__parser = parser
            self.fileName = CONFIG_FILE

    def get_section(self):
        p = self.__parser
        result = []
        for s in p.sections():
            result.append('{0}'.format(s))
        return result

    def get_info(self, config_section):
        p = self.__parser
        self.section = config_section
        self.url = p.get(config_section, 'url')
        self.imgexpr = p.get(config_section, 'imgexpr')
        self.imgattr1 = p.get(config_section, 'imgattr1')
        self.imgattr2 = p.get(config_section, 'imgattr2')
        self.destination = p.get(config_section, 'destination')
        self.createzip = p.get(config_section, 'createzip')
        self.pagesnumber = p.get(config_section, 'pagesnumber')

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

EDIT: Я использую этот код с простым скреблем изображений. Через get_section я возвращаю все разделы в файле конфигурации, а затем перебираю их, чтобы посещать каждый сайт, с которого я очищаю изображения. Для каждой итерации я делаю вызов get_section, чтобы получить настройки конфигурации для каждого раздела в файле конфигурации. Если кто-то может придумать другой подход, все будет хорошо! Спасибо!

Ответы

Ответ 1

Я определенно объявляю все переменные экземпляра в __init__. Не делать этого приводит к повышенной сложности и потенциальным неожиданным побочным эффектам.

Чтобы предоставить альтернативную точку зрения Дэвида Холла в плане доступа, это из руководство по стилю Google Python.

Контроль доступа:

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

С другой стороны, если доступ более сложный или стоимость доступа переменная значительна, вы должны использовать вызовы функций (следующие правила именования), такие как get_foo() и set_foo(). Если прошлое поведение допускает доступ через свойство, не связывает новое функции доступа к свойству. Любой код, все еще пытающийся доступ к переменной по старому методу должен заметно нарушаться, чтобы они были осознал изменение сложности.

От PEP8

Для простых атрибутов публичных данных лучше всего имя атрибута, без сложных методов accessor/mutator. Хранить в что Python обеспечивает легкий путь к будущему вы обнаружите, что простой атрибут данных должен функционировать поведение. В этом случае используйте свойства, чтобы скрыть функциональные реализация за простейшим синтаксисом доступа к атрибутам данных.

Примечание 1: Свойства работают только в классах нового стиля.

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

Примечание 3: Избегайте использования свойств для дорогостоящих вычислений операции; нотация атрибута заставляет вызывающего доступ (относительно) дешевый.

Python не является java/С#, и он имеет очень сильные идеи о том, как можно было выглядеть и писать. Если вы кодируете python, имеет смысл заставить его выглядеть и чувствовать себя как python. Другие люди смогут лучше понять ваш код, и вы сможете лучше понять и другие коды на Python.

Ответ 2

Я бы предпочел установить все переменные экземпляра в конструкторе, имея функции типа get_info(), которые необходимы, чтобы поставить класс в допустимое состояние.

С переменными public экземпляра, которые создаются только при вызове методов, таких как ваш get_info(), вы создаете класс, который является немного минной поля для использования.

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

Со свойствами или функциями стиля вы поощряете пользователей класса проходить через определенный интерфейс и улучшать инкапсуляцию 1.

Как только у вас есть инкапсуляция переменных экземпляра, вы даете себе возможность сделать что-то большее, чем просто выбросить исключение NameError, вы можете сами вызвать get_info() или выбросить настраиваемое исключение.


1. Вы не можете обеспечить 100% -ную инкапсуляцию с помощью Python, поскольку переменные частного экземпляра, обозначенные ведущим двойным подчеркиванием, являются только частными по соглашениям