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

"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?

Отвечаю: Потому что принцип инкапсуляции (ООП) говорит иначе!

Каков наилучший способ?

4b9b3361

Ответ 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. Дорога лучше.:)