"Частный" (реализация) класс в Python
я кодирую небольшой модуль Python, состоящий из двух частей:
- некоторые функции, определяющие открытый интерфейс,
- класс реализации, используемый вышеуказанными функциями, но который не имеет смысла вне модуля.
сначала я решил "скрыть" этот класс реализации, определив его внутри функции, используя его, но это затрудняет читаемость и не может использоваться, если несколько функций повторно используют один и тот же класс.
Так, в помимо комментариев и документов, есть ли механизм для обозначения класса как "частного" или "внутреннего"? Я знаю о механизме подчеркивания, но, как я понимаю, он применяется только к переменным, функциям и именам методов.
7 ответов:
используйте один префикс подчеркивания:
class _Internal: ...
это официальное соглашение Python для "внутренних" символов; "from module import *" не импортирует объекты с префиксом подчеркивания.
изменить: ссылка на соглашение об одном подчеркивании
короче:
вы не можете обеспечить соблюдение конфиденциальности. В Python нет частных классов/методов/функций. По крайней мере, не строгая конфиденциальность, как и в других языках, таких как Java.
вы можете только указать/предложить конфиденциальность. Это следует за соглашением. Соглашение python для обозначения класса / функции / метода как частного состоит в том, чтобы предварить его _ (подчеркивание). Например,
def _myfunc()
илиclass _MyClass:
. Вы также можете создайте псевдо-конфиденциальность, предваряя метод двумя подчеркиваниями (например:__foo
). Вы не можете получить доступ к методу напрямую, но вы все равно можете вызвать его через специальный префикс, используя имя класса (например:_classname__foo
). Поэтому лучшее, что вы можете сделать, это указать/предложить конфиденциальность, а не применять ее.Python похож на perl в этом отношении. Перефразируя известную строку о конфиденциальности из книги на Perl, философия заключается в том, что вы должны держаться подальше от гостиной, потому что вы не пригласили, не потому что он оборонялся из дробовика.
для получения дополнительной информации:
- частные переменныеДокументация Python
- функциипогружение в Python, Марк Пилигрим
- почему "частные" методы Python на самом деле не частная? StackOverflow вопрос 70528
определение
__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
. Так что на самом деле, если вы знаете искаженное имя, вы можете использовать "частный" объект в любом случае. см. здесь. и конечно, вы можете вручную импортировать "внутренние" классы, если хотите).