Python: "Частный" модуль в пакете
У меня есть посылка mypack
с модулями mod_a
а также mod_b
в этом. Я намерен сам пакет и mod_a
свободно ввозиться:
import mypack
import mypack.mod_a
Тем не менее, я хотел бы сохранить mod_b
для исключительного использования mypack
, Это потому, что он существует просто для организации внутреннего кода последнего.
Мой первый вопрос: является ли общепринятой практикой в программировании на Python иметь такие "частные" модули?
Если да, мой второй вопрос: как лучше донести это намерение до клиента? Должен ли я ставить перед именем подчеркивание (т.е. _mod_b
)? Или было бы неплохо объявить подпакет private
и разместить все такие модули там?
4 ответа
Решение, на котором я остановился, заключается в создании подпакета "private" и размещении там всех модулей, которые я хочу скрыть. Таким образом, они остаются убранными, оставляя mypack
Список модулей чище и проще для разбора.
Для меня это тоже не выглядит пифоничным.
Я префикс частных модулей с подчеркиванием, чтобы сообщить намерение пользователю. В вашем случае это будет mypack._mod_b
Это в том же духе (но не полностью аналогично) рекомендации PEP8 называть модули расширения C с начальным подчеркиванием, когда оно заключено в модуль Python; т.е. _socket
а также socket
,
Хотя не существует явных закрытых ключевых слов, существует соглашение, согласно которому закрытые функции должны начинаться с одного подчеркивания, но двойное начальное подчеркивание сделает это таким образом, чтобы другие не могли легко вызвать функцию извне модуля. Смотрите следующее из PEP 8
- _single_leading_underscore: weak "internal use" indicator. E.g. "from M
import *" does not import objects whose name starts with an underscore.
- single_trailing_underscore_: used by convention to avoid conflicts with
Python keyword, e.g.
Tkinter.Toplevel(master, class_='ClassName')
- __double_leading_underscore: when naming a class attribute, invokes name
mangling (inside class FooBar, __boo becomes _FooBar__boo; see below).
- __double_leading_and_trailing_underscore__: "magic" objects or
attributes that live in user-controlled namespaces. E.g. __init__,
__import__ or __file__. Never invent such names; only use them
as documented.
Чтобы сделать весь модуль приватным, не включайте его __init__.py
файл.
Одна вещь, о которой следует помнить в этом сценарии, - это косвенный импорт. Если вmypack
ты
from mypack._mod_b import foo
foo()
Тогда пользователь может
from mypack import foo
foo()
и не будь мудрее. Я рекомендую импортировать как
from mypack import _mod_b
_mod_b.foo()
тогда пользователь сразу увидит красный флаг, когда попытается
from mypack import _mod_b
Что касается фактической структуры каталогов, вы можете даже расширить ответ Джереми на _package_of_this_kind
пакет, где все, что может иметь любые "модификаторы доступа", которые вам нравятся - пользователи будут знать, что есть драконы
Python строго не знает и не поддерживает "частные" или "защищенные" методы или классы. Существует соглашение, что методы с префиксом с одним подчеркиванием не являются частью официального API, но я бы не стал делать это с классами или файлами - это ужасно.
Если кому-то действительно нужно создать подкласс или получить доступ к mod_b, зачем мешать ему / ей делать это? Вы всегда можете предоставить предпочтительный API в своей документации и документе в своем модуле, чтобы вам не пришлось обращаться к нему напрямую и использовать mypack вместо него.