Ответ 1
Если вы действительно хотите удалить имена из пространства имен, вы можете просто использовать инструкцию del
на них, и они исчезнут, как ветер.
Я хочу, чтобы интерфейс некоторого модуля содержал определенное количество функций и классов (и ничего больше). Я мог бы реализовать все из них в одном файле и легко получить интерфейс, который я хочу. Но так как есть много кода, я бы предпочел разбить все на несколько файлов, скажем
mypackage/
__init__.py
a.py
b.py
c.py
d.py
Чтобы получить желаемый интерфейс, я определяю файл __init__.py
для пакета, который импортирует все общедоступные символы из a
, b
, c
и d
:
from a import func_a1, func_a2, ClassA1, ClassA2
from b import func_b1, func_b2, ClassB1, ClassB2
from c import func_c1, func_c2, ClassC1, ClassC2
from d import func_d1, func_d2, ClassD1, ClassD2
Если я импортирую пакет, используя
import mypackage
пространство имен пакетов также содержит символы a
, b
, c
и d
. Эти имена являются деталями реализации, а не частью моего интерфейса. Я не хочу, чтобы они отображались как "общедоступные" символы. Каков наилучший способ избавиться от них?
Параметры, которые я рассмотрел,
Используйте только один модуль вместо пакета. Интерфейс будет выглядеть отлично, но реализация станет менее понятной, чем сейчас.
Добавьте строку
del a, b, c, d
до конца __init__.py
. Работает нормально, но кажется взломанным. (Например, вы больше не можете import __init__
, который работает без этой строки.)
Переименуйте a
, b
, c
и d
в _a
, _b
, _c
и _d
. Теперь они включены в пространство имен mypackage
как символы "private", с которыми я в порядке, но мне кажется странным, что все мои имена файлов начинаются с подчеркивания (на самом деле, конечно, более четырех подмодулей).
Любые лучшие предложения? Или мысли о том, какой вариант предпочтительнее?
Или я просто анал и не должен заботиться обо всем этом?
Если вы действительно хотите удалить имена из пространства имен, вы можете просто использовать инструкцию del
на них, и они исчезнут, как ветер.
Если некоторые из файлов в пакете действительно являются деталями реализации, продолжайте и придерживайте знак подчеркивания перед ними - это то, для чего мы их используем.
Например, если вы посмотрите в ctypes
, вы увидите
__init__.py
==================================================
"""create and manipulate C data types in Python"""
import os as _os, sys as _sys
__version__ = "1.1.0"
from _ctypes import Union, Structure, Array
from _ctypes import _Pointer
from _ctypes import CFuncPtr as _CFuncPtr
...
Как вы можете видеть, даже os
и sys
стали деталями реализации в этом файле.
Из http://docs.python.org/tutorial/modules.html:
В заявлении import используется следующее соглашение: если пакеты __init__.py определяет список с именем __all__, он считается списком имен модулей, которые должны быть импортированы когда из импорта пакета * встречаются.
В своем mypackage/__init__.py
попробуйте добавить это:
# add this line, replace "..." with the rest of the definitions
# you want made public
__all__ = ['func_a1', 'func_a2', 'ClassA1', 'ClassA2', ...]
from a import func_a1, func_a2, ClassA1, ClassA2
from b import func_b1, func_b2, ClassB1, ClassB2
from c import func_c1, func_c2, ClassC1, ClassC2
from d import func_d1, func_d2, ClassD1, ClassD2
Вот решение, вдохновленное однофункциональными модулями Javascript:
def __init__module():
from os import path
def _module_export_1():
return path.abspath('../foo')
def _module_export_2():
return path.relpath('foo/bar', 'foo')
g = globals()
g['module_export_1'] = _module_export_1
g['module_export_2'] = _module_export_2
__init__module()
Хотя модулю необходимо импортировать "путь" из os, "путь" не загрязняет пространство имен модулей. Единственным прорывом в пространстве имен модулей является __init_module(), который явно помечен частным префиксом с двойным подчеркиванием.
Другой вариант - импортировать необходимые модули в верхней части каждой функции, а не в верхнюю часть вашего модуля. После первого импорта модуля, последующий импорт - это просто поиск в словаре sys.modules.
Но я согласен с другими комментаторами здесь - соглашение Python не должно беспокоиться о загрязнении пространства имен модулей и просто сделать очевидным для пользователей вашего модуля, какие части пространства имен являются вашим общедоступным API и которые являются внутренними.