Как создать пакет пространства имен в Python?
в Python пакет пространства имен позволяет распространять код Python среди нескольких проектов. Это полезно, когда вы хотите выпустить соответствующие библиотеки в виде отдельных загрузок. Например, с каталогами Package-1
и Package-2
на PYTHONPATH
,
Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py
конечный пользователь может import namespace.module1
и import namespace.module2
.
как лучше всего определить пакет пространства имен, чтобы несколько продуктов Python могли определять модули в этом пространстве имен?
5 ответов
TL; DR:
на Python 3.3 вам не нужно ничего делать, просто не кладите __init__.py
в директории пакета и он будет просто работать. На pre-3.3, выберите pkgutil.extend_path()
- решение pkg_resources.declare_namespace()
один, потому что он защищен от будущего и уже совместим с неявными пакетами пространства имен.
Python 3.3 представляет неявные пакеты пространств имен, см. PEP 420.
это означает, что теперь есть три типа объектов это может быть создано import foo
:
- модуль, представленный
- обычный пакет, представленный каталогом
foo
содержащий - пакет пространства имен, представленный одним или несколькими каталогами
foo
без__init__.py
файлы
пакеты тоже являются модулями, но здесь я имею в виду" непакетный модуль", когда говорю"модуль".
сначала он сканирует sys.path
для модуля или обычная упаковка. Если это удается, он прекращает поиск и создает и инициализирует модуль или пакет. Если он не нашел модуля или обычного пакета, но нашел хотя бы один каталог, он создает и инициализирует пакет пространства имен.
модули и обычные пакеты имеют __file__
установить на были созданы. Пакеты Regular и namespace имеют __path__
установите в каталог или каталоги, из которых они были созданы.
когда вы import foo.bar
выше поиск происходит сначала для foo
, то если пакет был найден, поиск bar
осуществляется с foo.__path__
как путь поиска вместо sys.path
. Если foo.bar
найдено foo
и foo.bar
создаются и инициализируются.
Итак, как смешиваются обычные пакеты и пакеты пространства имен? Обычно они этого не делают, но старые pkgutil
явный метод пакета пространства имен был расширен, чтобы включить неявные пакеты пространства имен.
если у вас уже есть обычный пакет это имеет __init__.py
такой:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
... поведение legacy заключается в добавлении любого другого обычный пакеты по искомому пути к своему __path__
. Но в Python 3.3 он также добавляет пакеты пространств имен.
так что вы можете иметь следующую структуру каталогов:
├── path1
│ └── package
│ ├── __init__.py
│ └── foo.py
├── path2
│ └── package
│ └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
... и пока эти двое ... --2--> есть extend_path
строки (и path1
, path2
и path3
в своем sys.path
) import package.foo
, import package.bar
и import package.baz
все работа.
pkg_resources.declare_namespace(__name__)
не был обновлен для включения неявных пакетов пространства имен.
есть стандартный модуль, называемый pkgutil, С помощью которого вы можно "добавить" модули в заданное пространство имен.
со структурой каталогов, которую вы предоставили:
Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py
вы должны поместить эти две строки в оба Package-1/namespace/__init__.py
и Package-2/namespace/__init__.py
(*):
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
(* поскольку-если вы не указываете зависимость между ними - вы не знаете, какой из них будет распознан первым-см. PEP 420 для получения дополнительной информации)
как документация говорит:
это добавит к пакету
__path__
все подкаталоги каталогов наsys.path
назван в честь пакета.
С этого момента вы сможете распространять эти два пакета независимо друг от друга.
этот раздел должен быть довольно понятным.
короче говоря, поместите код пространства имен в __init__.py
, update setup.py
чтобы объявить пространство имен,и вы можете идти.
Это старый вопрос, но кто-то недавно прокомментировал мой блог, что моя публикация о пакетах пространств имен по-прежнему актуальна, поэтому я подумал, что я буду ссылаться на нее здесь, поскольку она дает практический пример того, как это сделать:
http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb
это ссылки на эту статью для основных кишок того, что происходит on:
http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package
на __import__("pkg_resources").declare_namespace(__name__)
трюк в значительной степени управляет управлением плагинами в TiddlyWeb и до сих пор, кажется, работает.
у вас есть концепции пространства имен Python назад к фронту, в python невозможно поместить пакеты в модули. Пакеты содержат модули, а не наоборот.
пакет Python-это просто папка, содержащая . Модуль-это любой другой файл в пакете (или непосредственно на PYTHONPATH
), имеет