2010-04-29 2 views
2

Есть ли общее соглашение об экспонировании членов в классах Python? Я знаю, что это случай «это зависит», но, возможно, существует эмпирическое правило.Выявление членов или их закрытие в 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?

+0

1) это зависит от 2) детей -> детей. – Stephen

+0

uups! исправлено множественное число – deamon

ответ

1

«Это зависит».

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

5

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

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

3

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

2

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

0

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

class Node: 

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

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

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

0

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

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

>>> node=Node() 
>>> node._Node__children 
[] 
2
  • Ответ, конечно же, "это зависит". Если бы я предполагал, я бы использовал метод 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):, так что я использую нового стиля классов. Классы нового стиля работают немного более естественным образом и имеют несколько функций в классах старого стиля.

Смежные вопросы