TL; DR:
Unter Python 3.3 müssen Sie nichts tun, nur keine __init__.pyin Ihre Namespace-Paketverzeichnisse einfügen, und es wird einfach funktionieren. Wählen Sie vor Version 3.3 die pkgutil.extend_path()Lösung aus pkg_resources.declare_namespace(), da sie zukunftssicher und bereits mit impliziten Namespace-Paketen kompatibel ist.
Python 3.3 führt implizite Namespace-Pakete ein, siehe PEP 420 .
Dies bedeutet, dass es jetzt drei Objekttypen gibt, die von einem erstellt werden können import foo:
- Ein Modul, das durch eine
foo.pyDatei dargestellt wird
- Ein reguläres Paket, dargestellt durch ein Verzeichnis,
foodas eine __init__.pyDatei enthält
- Ein Namespace-Paket, das durch ein oder mehrere Verzeichnisse
fooohne __init__.pyDateien dargestellt wird
Pakete sind auch Module, aber hier meine ich "Nicht-Paket-Modul", wenn ich "Modul" sage.
Zuerst wird sys.pathnach einem Modul oder einem regulären Paket gesucht. Wenn dies erfolgreich ist, wird die Suche beendet und das Modul oder Paket erstellt und initialisiert. Wenn kein Modul oder reguläres Paket gefunden wurde, aber mindestens ein Verzeichnis gefunden wurde, wird ein Namespace-Paket erstellt und initialisiert.
Module und reguläre Pakete haben __file__die .pyDatei festgelegt, aus der sie erstellt wurden. Reguläre Pakete und Namespace-Pakete haben __path__das Verzeichnis oder die Verzeichnisse festgelegt, aus denen sie erstellt wurden.
Wenn Sie das tun import foo.bar, geschieht das über den Such zuerst foo, dann , wenn ein Paket gefunden wurde, für die Suche barmit getan wird foo.__path__als Suchpfad statt sys.path. If foo.barwird gefunden foound foo.barerstellt und initialisiert.
Wie mischen sich reguläre Pakete und Namespace-Pakete? Normalerweise nicht, aber die alte pkgutilexplizite Namespace-Paketmethode wurde um implizite Namespace-Pakete erweitert.
Wenn Sie ein reguläres Paket haben, das Folgendes hat __init__.py:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
... das Legacy-Verhalten besteht darin, alle anderen regulären Pakete auf dem gesuchten Pfad zu seinem hinzuzufügen __path__. In Python 3.3 werden jedoch auch Namespace-Pakete hinzugefügt.
Sie können also die folgende Verzeichnisstruktur haben:
├── path1
│ └── package
│ ├── __init__.py
│ └── foo.py
├── path2
│ └── package
│ └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
... und so lange , wie die beiden __init__.pydie haben extend_pathLinien (und path1, path2und path3sind in Ihrem sys.path) import package.foo, import package.barund import package.bazwird alle Arbeit.
pkg_resources.declare_namespace(__name__) wurde nicht aktualisiert, um implizite Namespace-Pakete einzuschließen.