"Частный" (реализация) класс в Python


я кодирую небольшой модуль Python, состоящий из двух частей:

  • некоторые функции, определяющие открытый интерфейс,
  • класс реализации, используемый вышеуказанными функциями, но который не имеет смысла вне модуля.

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

Так, в помимо комментариев и документов, есть ли механизм для обозначения класса как "частного" или "внутреннего"? Я знаю о механизме подчеркивания, но, как я понимаю, он применяется только к переменным, функциям и именам методов.

7 82

7 ответов:

используйте один префикс подчеркивания:

class _Internal:
    ...

это официальное соглашение Python для "внутренних" символов; "from module import *" не импортирует объекты с префиксом подчеркивания.

изменить: ссылка на соглашение об одном подчеркивании

короче:

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

  2. вы можете только указать/предложить конфиденциальность. Это следует за соглашением. Соглашение python для обозначения класса / функции / метода как частного состоит в том, чтобы предварить его _ (подчеркивание). Например, def _myfunc() или class _MyClass:. Вы также можете создайте псевдо-конфиденциальность, предваряя метод двумя подчеркиваниями (например:__foo). Вы не можете получить доступ к методу напрямую, но вы все равно можете вызвать его через специальный префикс, используя имя класса (например:_classname__foo). Поэтому лучшее, что вы можете сделать, это указать/предложить конфиденциальность, а не применять ее.

Python похож на perl в этом отношении. Перефразируя известную строку о конфиденциальности из книги на Perl, философия заключается в том, что вы должны держаться подальше от гостиной, потому что вы не пригласили, не потому что он оборонялся из дробовика.

для получения дополнительной информации:

определение __all__ список имен, которые вы хотите экспортировать (документации).

__all__ = ['public_class'] # don't add here the 'implementation_class'

шаблон, который я иногда использую это:

определить класс:

class x(object):
    def doThis(self):
        ...
    def doThat(self):
        ...

создайте экземпляр класса, перезаписав имя класса:

x = x()

определите символы, которые предоставляют функциональность:

doThis = x.doThis
doThat = x.doThat

удалить сам экземпляр:

del x

теперь у вас есть модуль, который предоставляет только ваши публичные функции.

соглашение является добавлением " _ " к внутренним классам, функциям и переменным.

чтобы решить проблему соглашений о дизайне, и, как сказал Кристофер, на самом деле нет такой вещи, как "частный" в Python. Это может показаться запутанным для кого-то, кто приходит с фона C/C++ (как и я некоторое время назад), но в конце концов вы, вероятно, поймете, что следующих соглашений достаточно.

видя что-то, имеющее подчеркивание спереди, должно быть достаточно хорошим намеком, чтобы не использовать его напрямую. Если вы обеспокоены загромождением help(MyClass) выход (который является то, что все смотрит при поиске о том, как использовать класс), подчеркнутые атрибуты/классы не включены туда, поэтому вы в конечном итоге просто описываете свой "публичный" интерфейс.

плюс, имея все публичное имеет свои собственные удивительные льготы, как, например, вы можете модульный тест почти ничего извне (что вы не можете сделать с C/C++ частных конструкций).

используйте два символа подчеркивания для префикса имен" частных " идентификаторов. Для классов в модуле используйте одно начальное подчеркивание, и они не будут импортированы с помощью "from module import *".

class _MyInternalClass:
    def __my_private_method:
        pass

(в Python нет такой вещи, как true "private". Например, Python просто автоматически искажает имена членов класса с двойным подчеркиванием, чтобы быть __clssname_mymember. Так что на самом деле, если вы знаете искаженное имя, вы можете использовать "частный" объект в любом случае. см. здесь. и конечно, вы можете вручную импортировать "внутренние" классы, если хотите).