W Pythonie pakiet przestrzeni nazw umożliwia rozpowszechnianie kodu Pythona między kilkoma projektami. Jest to przydatne, gdy chcesz zwolnić powiązane biblioteki jako osobne pliki do pobrania. Na przykład, w katalogach Package-1
i Package-2
na PYTHONPATH
,
Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py
użytkownik końcowy może import namespace.module1
i import namespace.module2
.
Jaki jest najlepszy sposób zdefiniowania pakietu przestrzeni nazw, aby więcej niż jeden produkt Pythona mógł definiować moduły w tej przestrzeni nazw?
python
namespaces
package
joeforker
źródło
źródło
Odpowiedzi:
TL; DR:
W Pythonie 3.3 nie musisz nic robić, po prostu nie umieszczaj żadnych
__init__.py
w katalogach pakietów przestrzeni nazw i po prostu zadziała. W wersjach wcześniejszych niż 3.3 wybierzpkgutil.extend_path()
rozwiązanie zamiast tegopkg_resources.declare_namespace()
, ponieważ jest przyszłościowe i już jest zgodne z niejawnymi pakietami przestrzeni nazw.Python 3.3 wprowadza niejawne pakiety przestrzeni nazw, zobacz PEP 420 .
Oznacza to, że istnieją teraz trzy typy obiektów, które można utworzyć za pomocą
import foo
:foo.py
plikfoo
zawierający__init__.py
plikfoo
bez żadnych__init__.py
plikówPakiety też są modułami, ale mam tu na myśli „moduł nie będący pakietem”, kiedy mówię „moduł”.
Najpierw skanuje w
sys.path
poszukiwaniu modułu lub zwykłego pakietu. Jeśli się powiedzie, zatrzymuje wyszukiwanie i tworzy oraz inicjalizuje moduł lub pakiet. Jeśli nie znalazł modułu lub zwykłego pakietu, ale znalazł przynajmniej jeden katalog, tworzy i inicjalizuje pakiet przestrzeni nazw.Moduły i zwykłe pakiety mają
__file__
ustawiony.py
plik, z którego zostały utworzone. Pakiety zwykłe iz przestrzeni nazw__path__
ustawiły katalog lub katalogi, z których zostały utworzone.Kiedy to zrobisz
import foo.bar
, powyższe wyszukiwanie odbywa się najpierw dlafoo
, a następnie, jeśli pakiet został znaleziony, wyszukiwaniebar
jest wykonywanefoo.__path__
za pomocą ścieżki wyszukiwania zamiastsys.path
. Jeślifoo.bar
zostanie znaleziony,foo
ifoo.bar
są tworzone i inicjalizowane.Jak więc mieszają się zwykłe pakiety i pakiety przestrzeni nazw? Zwykle tak nie jest, ale stara
pkgutil
jawna metoda pakietu przestrzeni nazw została rozszerzona o niejawne pakiety przestrzeni nazw.Jeśli masz istniejący zwykły pakiet, który ma taki
__init__.py
wygląd:... starsze zachowanie polega na dodaniu innych zwykłych pakietów na przeszukiwanej ścieżce do ich
__path__
. Ale w Pythonie 3.3 dodaje również pakiety przestrzeni nazw.Możesz więc mieć następującą strukturę katalogów:
... i tak długo, jak obaj
__init__.py
mająextend_path
linie (ipath1
,path2
ipath3
są w twoimsys.path
)import package.foo
,import package.bar
iimport package.baz
wszystko będzie działać.pkg_resources.declare_namespace(__name__)
nie został zaktualizowany w celu uwzględnienia niejawnych pakietów przestrzeni nazw.źródło
namespace_packages
opcji? A__import__('pkg_resources').declare_namespace(__name__)
co?namespace_packages=['package']
wsetup.py
?namespace_packages=['package']
setup.py doda anamespace_packages.txt
do EGG-INFO. Nadal nie znam skutków…pkg_resources.declare_namespace
overpkgutil.extend_path
jest to, że będzie nadal monitorowaćsys.path
. W ten sposób, jeśli nowy element zostanie dodanysys.path
po pierwszym załadowaniu pakietu w przestrzeni nazw, pakiety w przestrzeni nazw w tym nowym elemencie ścieżki nadal będą mogły być ładowane. (Zaletą używania__import__('pkg_resources')
nadwyżkiimport pkg_resources
jest to, że niepkg_resources
zostaniesz ujawniony jakomy_namespace_pkg.pkg_resources
.)sys.path
. Posys.path
zmianach sprawdza, czy ma to wpływ na__path__
jakąkolwiek przestrzeń nazw, a jeśli tak, aktualizuje te__path__
właściwości.Istnieje standardowy moduł o nazwie pkgutil , za pomocą którego można „dołączać” moduły do danej przestrzeni nazw.
Dzięki podanej strukturze katalogów:
Powinieneś umieścić te dwie linie w obu
Package-1/namespace/__init__.py
iPackage-2/namespace/__init__.py
(*):(* ponieważ - jeśli nie określisz zależności między nimi - nie wiesz, które z nich zostaną rozpoznane jako pierwsze - zobacz PEP 420, aby uzyskać więcej informacji)
Jako dokumentacja mówi :
Od teraz powinieneś móc dystrybuować te dwa pakiety niezależnie.
źródło
__import__
w tym przypadku jest uważany za zły styl, ponieważ można go łatwo zastąpić zwykłą instrukcją importu. Co więcej, pkg_resources jest biblioteką niestandardową. Jest dostarczany z narzędziami konfiguracyjnymi, więc nie stanowi to problemu. Szybkie wyszukiwanie w Google ujawnia, że pkgutil został wprowadzony w wersji 2.5, a pkg_resources jest starszy niż. Niemniej jednak pkgutil jest oficjalnie uznanym rozwiązaniem. Włączenie pkg_resources zostało w rzeczywistości odrzucone w PEP 365.Package-1/namespace/__init__.py
i podPackage-2/namespace/__init__.py
warunkiem, że nie wiemy, który katalog Package jest wymieniony jako pierwszy?Ta sekcja powinna być dość oczywista.
Krótko mówiąc, umieść kod przestrzeni nazw
__init__.py
, zaktualizuj,setup.py
aby zadeklarować przestrzeń nazw i możesz zaczynać.źródło
To stare pytanie, ale ktoś niedawno skomentował na moim blogu, że mój post dotyczący pakietów przestrzeni nazw jest nadal aktualny, więc pomyślałem, że umieściłbym do niego link, ponieważ zawiera praktyczny przykład, jak to zrobić:
https://web.archive.org/web/20150425043954/http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb
To prowadzi do tego artykułu, aby poznać główne aspekty tego, co się dzieje:
http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package
__import__("pkg_resources").declare_namespace(__name__)
Trik jest dość dużo napędza zarządzania wtyczek w TiddlyWeb i do tej pory wydaje się być obecnie pracuje.źródło
Masz koncepcje przestrzeni nazw Pythona od początku do końca, w Pythonie nie jest możliwe umieszczanie pakietów w modułach. Pakiety zawierają moduły, a nie na odwrót.
Pakiet Pythona to po prostu folder zawierający
__init__.py
plik. Moduł to dowolny inny plik w pakiecie (lub bezpośrednio wPYTHONPATH
), który ma.py
rozszerzenie. W twoim przykładzie masz dwa pakiety, ale nie zdefiniowano żadnych modułów. Jeśli weźmiesz pod uwagę, że pakiet to folder systemu plików, a moduł to plik, zobaczysz, dlaczego pakiety zawierają moduły, a nie na odwrót.W twoim przykładzie zakładając, że Package-1 i Package-2 są folderami w systemie plików, które umieściłeś w ścieżce Pythona, możesz mieć następujące rzeczy:
Masz teraz jeden pakiet
namespace
z dwoma modułamimodule1
imodule2
. i jeśli nie masz dobrego powodu, prawdopodobnie powinieneś umieścić moduły w folderze i mieć tylko to na ścieżce Pythona, jak poniżej:źródło
zope.x
kilka powiązanych pakietów wydawanych jako osobne pliki do pobrania.