TL; DR:
W Pythonie 3.3 nie musisz nic robić, po prostu nie umieszczaj żadnych __init__.pyw katalogach pakietów przestrzeni nazw i po prostu zadziała. W wersjach wcześniejszych niż 3.3 wybierz pkgutil.extend_path()rozwiązanie zamiast tego pkg_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:
- Moduł reprezentowany przez
foo.pyplik
- Zwykły pakiet reprezentowany przez katalog
foozawierający __init__.pyplik
- Pakiet przestrzeni nazw, reprezentowany przez jeden lub więcej katalogów
foobez żadnych __init__.pyplików
Pakiety też są modułami, ale mam tu na myśli „moduł nie będący pakietem”, kiedy mówię „moduł”.
Najpierw skanuje w sys.pathposzukiwaniu 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 .pyplik, 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 dla foo, a następnie, jeśli pakiet został znaleziony, wyszukiwanie barjest wykonywane foo.__path__za pomocą ścieżki wyszukiwania zamiast sys.path. Jeśli foo.barzostanie znaleziony, fooi foo.barsą tworzone i inicjalizowane.
Jak więc mieszają się zwykłe pakiety i pakiety przestrzeni nazw? Zwykle tak nie jest, ale stara pkgutiljawna 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__.pywygląd:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
... 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:
├── path1
│ └── package
│ ├── __init__.py
│ └── foo.py
├── path2
│ └── package
│ └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
... i tak długo, jak obaj __init__.pymają extend_pathlinie (i path1, path2i path3są w twoim sys.path) import package.foo, import package.bari import package.bazwszystko będzie działać.
pkg_resources.declare_namespace(__name__) nie został zaktualizowany w celu uwzględnienia niejawnych pakietów przestrzeni nazw.