«Закрытый» (реализация) класс в Python - PullRequest
91 голосов
/ 15 февраля 2009

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

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

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

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

Ответы [ 7 ]

144 голосов
/ 15 февраля 2009

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

class _Internal:
    ...

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

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

58 голосов
/ 15 февраля 2009

Короче говоря:

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

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

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

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

35 голосов
/ 15 февраля 2009

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

__all__ = ['public_class'] # don't add here the 'implementation_class'
9 голосов
/ 15 февраля 2009

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

Определите класс:

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

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

x = x()

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

doThis = x.doThis
doThat = x.doThat

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

del x

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

8 голосов
/ 15 февраля 2009

Условное обозначение предваряется "_" для внутренних классов, функций и переменных.

4 голосов
/ 15 февраля 2009

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

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

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

2 голосов
/ 15 февраля 2009

Используйте два подчеркивания для префикса имен «частных» идентификаторов. Для классов в модуле используйте одно начальное подчеркивание, и они не будут импортированы с использованием «из модуля импорта *».

class _MyInternalClass:
    def __my_private_method:
        pass

(В Python нет такой вещи, как истинное «личное». Например, Python просто автоматически изменяет имена членов класса с двойными подчеркиваниями на __clssname_mymember. В действительности, если вы знаете искаженное имя, вы можете использовать в любом случае «частная» сущность. См. здесь. И, конечно, вы можете вручную импортировать «внутренние» классы, если хотите).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...