Jak utworzyć pakiet przestrzeni nazw w Pythonie?

W Pythonie, pakiet przestrzeni nazw pozwala na rozprzestrzenianie kodu Pythona wśród kilku projektów. Jest to przydatne, gdy chcesz udostępnić powiązane biblioteki jako osobne pliki do pobrania. Na przykład z katalogami Package-1 i Package-2 w 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 na zdefiniowanie pakietu przestrzeni nazw, aby więcej niż jeden produkt Pythona mógł zdefiniować Moduły w tej przestrzeni nazw?

Author: joeforker, 2009-11-04

5 answers

TL; DR:

W Pythonie 3.3 nie musisz nic robić, po prostu nie umieszczaj żadnych __init__.py w swoich katalogach pakietów przestrzeni nazw, a to po prostu zadziała. W wersji pre-3.3 Wybierz rozwiązanie pkgutil.extend_path() zamiast pkg_resources.declare_namespace(), ponieważ jest przyszłościowe i jest już kompatybilne z domyślnymi pakietami przestrzeni nazw.


Python 3.3 wprowadza Ukryte Pakiety przestrzeni nazw, zobacz PEP 420 .

Oznacza to, że obecnie istnieją trzy typy obiektów, które mogą być tworzone przez import foo:

  • moduł reprezentowany przez plik foo.py
  • zwykły pakiet, reprezentowany przez katalog foo zawierający plik __init__.py
  • pakiet przestrzeni nazw reprezentowany przez jeden lub więcej katalogów foo bez żadnych plików __init__.py

Pakiety też są modułami, ale tutaj mam na myśli " non-package module "Kiedy mówię"module".

Najpierw skanuje sys.path W poszukiwaniu modułu lub zwykłego pakietu. Jeśli się powiedzie, przestaje wyszukiwać i tworzy i initalizuje moduł lub paczka. Jeśli nie znalazł żadnego modułu lub zwykłego pakietu, ale znalazł przynajmniej jeden katalog, tworzy i inicjalizuje pakiet przestrzeni nazw.

Moduły i zwykłe pakiety mają {[12] } ustawiony na .py Plik, z którego zostały utworzone. Pakiety zwykłe i przestrzenie nazw mają __path__ ustawione na katalog lub katalogi, z których zostały utworzone.

Kiedy wykonasz import foo.bar, powyższe wyszukiwanie odbywa się najpierw dla foo, Następnie jeśli pakiet został znaleziony, wyszukiwanie barodbywa się z foo.__path__ jako ścieżka wyszukiwania zamiast sys.path. Jeśli foo.bar zostanie znaleziony, foo i foo.bar zostaną utworzone i zainicjowane.

Więc jak zwykłe pakiety i przestrzenie nazw mieszają się? Zwykle tak nie jest, ale stara metoda jawnego pakietu przestrzeni nazw pkgutil została rozszerzona o domyślne Pakiety przestrzeni nazw.

Jeśli masz istniejący zwykły pakiet, który ma __init__.py w ten sposób:

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

... zachowanie starsze polega na dodaniu innych zwykłych pakietów na wyszukiwanej ścieżce do its __path__. Ale w Pythonie 3.3 dodaje również pakiety przestrzeni nazw.

Więc możesz mieć następującą strukturę katalogów:

├── path1
│   └── package
│       ├── __init__.py
│       └── foo.py
├── path2
│   └── package
│       └── bar.py
└── path3
    └── package
        ├── __init__.py
        └── baz.py

... i tak długo, jak dwie __init__.py mają extend_path linie (i path1, path2 i path3 są w Twoim sys.path) import package.foo, import package.bar i wszystko będzie działać.

pkg_resources.declare_namespace(__name__) nie został zaktualizowany, aby zawierał Ukryte Pakiety przestrzeni nazw.

 48
Author: clacke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-21 02:44:44

Istnieje standardowy moduł o nazwie pkgutil , z którym potrafi "dodawać" moduły do danej przestrzeni nazw.

Z podaną strukturą katalogów:

Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py

Należy umieścić te dwie linie w obu Package-1/namespace/__init__.py i Package-2/namespace/__init__.py (*):

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

(* ponieważ-jeśli nie podasz zależności między nimi - nie wiesz, który z nich zostanie rozpoznany jako pierwszy-zobacz PEP 420 aby uzyskać więcej informacji)

Jak mówi dokumentacja :

To doda do __path__ pakietu wszystkie podkatalogi katalogów na sys.path nazwane po pakiecie.

Od teraz powinieneś być w stanie dystrybuować te dwa pakiety niezależnie.

 75
Author: Mike Hordecki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-02 23:39:45

Ta sekcja powinna być dość oczywiste.

W skrócie, umieść kod przestrzeni nazw w __init__.py, zaktualizuj setup.py, aby zadeklarować przestrzeń nazw, i jesteś wolny.

 5
Author: iElectric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-28 19:47:05

To stare pytanie, ale ktoś ostatnio skomentował na moim blogu, że mój wpis o pakietach przestrzeni nazw jest nadal aktualny, więc pomyślałem, że linkuję do niego tutaj, ponieważ dostarcza praktycznego przykładu, jak to zrobić:

Http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb

Że linki do tego artykułu dla głównych wnętrzności tego, co się dzieje on:

Http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package

Sztuczka __import__("pkg_resources").declare_namespace(__name__) jest dość dużo napędza zarządzanie wtyczek w TiddlyWeb i jak dotąd wydaje się działać.

 3
Author: cdent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-05 15:30:52

Masz swoje koncepcje przestrzeni nazw Pythona z powrotem do przodu, nie jest możliwe w Pythonie umieszczanie pakietów w modułach. Pakiety zawierają moduły nie na odwrót.

Pakiet Pythona jest po prostu folderem zawierającym plik __init__.py. Moduł to każdy inny plik w pakiecie (lub bezpośrednio w PYTHONPATH), który ma rozszerzenie .py. Więc w twoim przykładzie masz dwa pakiety, ale nie zdefiniowano żadnych modułów. Jeśli uważasz, że pakiet jest folderem systemu plików, a moduł jest plikiem, to widzisz dlaczego pakiety zawierają moduły, a nie odwrotnie.

Więc w twoim przykładzie zakładając, że Package-1 i Package-2 są folderami w systemie plików, które umieściłeś na ścieżce Pythona, możesz mieć następujące:

Package-1/
  namespace/
  __init__.py
  module1.py
Package-2/
  namespace/
  __init__.py
  module2.py

Masz teraz jeden pakiet namespace z dwoma modułami module1 i module2. i chyba, że masz dobry powód, powinieneś umieścić moduły w folderze i mieć tylko to na ścieżce Pythona, jak poniżej:

Package-1/
  namespace/
  __init__.py
  module1.py
  module2.py
 -8
Author: Tendayi Mawushe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-04 18:58:42