"public" или "private" атрибут в Python? Каков наилучший способ?
В Python у меня есть следующий примерный класс:
class Foo:
self._attr = 0
@property
def attr(self):
return self._attr
@attr.setter
def attr(self, value):
self._attr = value
@attr.deleter
def attr(self):
del self._attr
Как вы можете видеть, у меня есть простой атрибут "private" "_attr" и свойство для доступа к нему. Существует много кодов для объявления простого частного атрибута, и я думаю, что он не соблюдает философию "KISS", чтобы объявить все атрибуты, подобные этому.
Итак, почему бы не объявить все мои атрибуты как общедоступные атрибуты, если мне не нужен конкретный getter/setter/deleter?
Отвечаю:
Потому что принцип инкапсуляции (ООП) говорит иначе!
Каков наилучший способ?
Ответы
Ответ 1
Как правило, код Python стремится придерживаться принципа Uniform Access. В частности, принятый подход:
- Экспортируйте свои переменные экземпляра напрямую, разрешив, например,
foo.x = 0
, а не foo.set_x(0)
- Если вам нужно обернуть доступ внутри методов, по какой-либо причине используйте
@property
, который сохраняет семантику доступа. То есть foo.x = 0
теперь вызывает foo.set_x(0)
.
Основным преимуществом этого подхода является то, что вызывающий абонент может это сделать:
foo.x += 1
хотя код действительно может быть выполнен:
foo.set_x(foo.get_x() + 1)
Первое утверждение бесконечно читаемо. Тем не менее, со свойствами вы можете добавить (в начале или в дальнейшем) управление доступом, которое вы получите со вторым подходом.
Обратите внимание, что переменные экземпляра, начинающиеся с одного символа подчеркивания, обычно являются частными. То есть подчеркивание сигнализирует другим разработчикам, что вы считаете ценность частной, и они не должны связываться с ней напрямую; однако ничто в этом языке не препятствует им возиться с ним напрямую.
Если вы используете двойной знак подчеркивания (например, __x
), Python немного обфускации имени. Однако переменная по-прежнему доступна извне класса, через ее запутанное имя. Это не по-настоящему личное. Это просто... более непрозрачно. И есть действительные аргументы против использования двойного подчеркивания; во-первых, это может затруднить отладку.
Ответ 2
Префикс "dunder" (двойной подчеркивание, __
) предотвращает доступ к атрибуту, за исключением аксессуаров.
class Foo():
def __init__(self):
self.__attr = 0
@property
def attr(self):
return self.__attr
@attr.setter
def attr(self, value):
self.__attr = value
@attr.deleter
def attr(self):
del self.__attr
Некоторые примеры:
>>> f = Foo()
>>> f.__attr # Not directly accessible.
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__attr'
>>> '__attr' in f.__dir__() # Not listed by __dir__()
False
>>> f.__getattribute__('__attr') # Not listed by __getattribute__()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__attr'
>>> f.attr # Accessible by implemented getter.
0
>>> f.attr = 'Presto' # Can be set by implemented setter.
>>> f.attr
'Presto'
>>> f.__attr = 'Tricky?' # Can we set it explicitly?
>>> f.attr # No. By doing that we have created a
'Presto' # new but unrelated attribute, same name.
Ответ 3
Совершенно просто, принципы ООП ошибочны. Почему это длительное обсуждение, которое ведет к flamewars и, вероятно, не соответствует теме для этого сайта.: -)
В Python нет частных атрибутов, вы не можете их защитить, и это никогда не является реальной проблемой. Так не надо. Легко!:)
Затем возникает вопрос: должен ли вы иметь лидирующий знак подчеркивания или нет. И в примере, который у вас здесь, вы определенно не должны. Ведущим подчеркиванием в Python является соглашение о том, что что-то является внутренним, а не частью API, и что вы должны использовать его на свой страх и риск. Это, очевидно, не так, но это общее и полезное соглашение.
Ответ 4
Python не имеет открытых или частных атрибутов. Все атрибуты доступны для всего кода.
self.attr = 0 #Done
Ваш метод никоим образом не делает _attr частным, это всего лишь часть обфускации.
Ответ 5
Как говорили другие, частные атрибуты на Python - это просто соглашение. Использование синтаксиса property
должно использоваться для специальной обработки, когда атрибуты связаны, изменены или удалены. Красота Python заключается в том, что вы можете начать с использования обычного связывания атрибутов, например, self.attr = 0
, и если в какой-то более поздний срок вы решите, что хотите ограничить значение attr, скажем 0 <= attr <=100
, вы можете сделать attr
свойство и определить метод, чтобы убедиться, что это условие истинно, без изменения любого пользовательского кода.
Ответ 6
Чтобы сделать атрибут private, вам просто нужно сделать self.__attr
class Foo:
self.__attr = 0
@property
def attr(self):
return self._attr
@attr.setter
def attr(self, value):
self._attr = value
@attr.deleter
def attr(self):
del self._attr
Ответ 7
В Python, если вам не требуется специальное поведение из атрибута, нет необходимости скрывать его за методами доступа. Если атрибут используется только для внутреннего использования, добавьте его с подчеркиванием.
Ответ 8
Хорошая вещь о свойствах заключается в том, что они дали вам действительно классный интерфейс для работы. Иногда бывает полезно получить свойство, основанное на каком-то другом (т.е. BMI определяется весом и высотой). Пользователь интерфейса не обязательно должен это знать.
Я предпочитаю этот путь, имея явные getters и seters, подобные Java. Дорога лучше.:)