Разоблачение членов или сделать их приватными в Python? - PullRequest
2 голосов
/ 29 апреля 2010

Существует ли общее соглашение о представлении членов в классах Python? Я знаю, что это случай «это зависит», но, возможно, есть эмпирическое правило.

Частный член:

class Node:

  def __init__(self):
    self.__children = []

  def add_children(self, *args):
    self.__children += args

node = Node()
node.add_children("one", "two")

Публичный участник:

class Node2:

  def __init__(self):
    self.children = []

node2 = Node2()
node2.children += "one", "two"

Если нет веских причин делать children личным, вы бы остановились на методе add_children?

Ответы [ 7 ]

5 голосов
/ 29 апреля 2010

Префикс «private» - это подчеркивание. __ используется для искажения имени и предотвращения некоторых проблем, например при использовании множественного наследования. Лично я никогда не использовал это.

В любом случае, участники по-прежнему будут доступны для общественности; это просто соглашение.

3 голосов
/ 29 апреля 2010

Я полагаю, что больше Pythonic оставляет участников открытыми, если у вас нет особых причин не делать этого на том основании, что код Python обычно не намерен ограничивать пользователя больше, чем необходимо.Вот почему, например, не существует такого понятия, как действительно частный член.

2 голосов
/ 29 апреля 2010
  • Ответ, конечно, «это зависит».Если бы я догадался, я бы использовал метод add_children.Задача класса - абстрагировать то, что вы делаете, от представления состояния, которое вы храните.my_node.add_children(a, b) - это операция, которую я бы прочитал как «добавить детей a и b в мой режим».my_node.children.extend([a, b]) заставляет пользователя думать о children как о списке и переходить внутрь экземпляра, чтобы изменить его.Это иногда, но реже, то, что вы хотите.Это также затрудняет изменение API, если вам в конечном итоге понадобится добавить потомков, чтобы сделать что-то дополнительное.

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

    Когда у меня есть атрибут, который я не хочу использовать в качестве части моего публичного API, я добавляю его префиксс одним подчеркиванием, например _foo.Это соглашение широко используется.

  • Я никогда не использую += со списками;Вместо этого я использую метод extend.Мне не нравится +=, потому что большинство людей используют extend и потому, что его работа немного сбивает с толку.a += b отличается от a = a + b двумя способами: первый изменяет исходный список, а второй создает новый список и связывает его с исходным именем, а во втором b должен быть списком, а в первом b может быть произвольно повторяемым.Я нахожу extend чище.

  • Я всегда наследую object, а не ничего, то есть class Node(object):, так что я использую классы нового стиля .Классы нового стиля работают немного более нативно и имеют несколько функций, которые классы старого стиля не делают.

2 голосов
/ 29 апреля 2010

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

1 голос
/ 29 апреля 2010

"Это зависит."

Серьезно. Если Node нужно что-то сделать при добавлении детей, вы бы хотели, чтобы первым было зафиксировано изменение и сделано то, что нужно сделать. Если это просто список, о котором вам не нужно беспокоиться об изменениях, переходите к последнему.

0 голосов
/ 29 апреля 2010

Соглашение состоит в том, чтобы ставить префикс перед одним подчеркиванием, однако это чисто рекомендательный код, и все еще возможно получить доступ к атрибуту, как и к любому другому. Иногда удобно, когда вы пишите юнит-тесты

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

>>> node=Node()
>>> node._Node__children
[]
0 голосов
/ 29 апреля 2010

Как вы сказали, это зависит. Обычно я предпочитаю иметь метод взаимодействия с классом, чтобы получить разделение между логикой программирования и ее реализацией. Следуя приведенному вами примеру, я напишу:

class Node:

  def __init__(self):
      self.childs = []

  def add_childs(self, *args):
      self.childs += args

потому что, если подкласс получит доступ к childs, он сможет без каких-либо странных переменных. Обычно я использую закрытые члены только со свойствами, чтобы создать кеш вычисляемого значения.

...