Лучшая практика при определении переменных экземпляра
Я новичок в 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, поскольку переменные частного экземпляра, обозначенные ведущим двойным подчеркиванием, являются только частными по соглашениям