In Python können Sie mit einem Namespace-Paket Python-Code auf mehrere Projekte verteilen. Dies ist nützlich, wenn Sie verwandte Bibliotheken als separate Downloads freigeben möchten. Zum Beispiel mit den Verzeichnissen Package-1
und Package-2
in PYTHONPATH
,
Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py
Der Endbenutzer kann import namespace.module1
und import namespace.module2
.
Wie kann ein Namespace-Paket am besten definiert werden, damit mehr als ein Python-Produkt Module in diesem Namespace definieren kann?
python
namespaces
package
Joeforker
quelle
quelle
Antworten:
TL; DR:
Unter Python 3.3 müssen Sie nichts tun, nur keine
__init__.py
in Ihre Namespace-Paketverzeichnisse einfügen, und es wird einfach funktionieren. Wählen Sie vor Version 3.3 diepkgutil.extend_path()
Lösung auspkg_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
:foo.py
Datei dargestellt wirdfoo
das eine__init__.py
Datei enthältfoo
ohne__init__.py
Dateien dargestellt wirdPakete sind auch Module, aber hier meine ich "Nicht-Paket-Modul", wenn ich "Modul" sage.
Zuerst wird
sys.path
nach 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.py
Datei 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 zuerstfoo
, dann , wenn ein Paket gefunden wurde, für die Suchebar
mit getan wirdfoo.__path__
als Suchpfad stattsys.path
. Iffoo.bar
wird gefundenfoo
undfoo.bar
erstellt und initialisiert.Wie mischen sich reguläre Pakete und Namespace-Pakete? Normalerweise nicht, aber die alte
pkgutil
explizite Namespace-Paketmethode wurde um implizite Namespace-Pakete erweitert.Wenn Sie ein reguläres Paket haben, das Folgendes hat
__init__.py
:... 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:
... und so lange , wie die beiden
__init__.py
die habenextend_path
Linien (undpath1
,path2
undpath3
sind in Ihremsys.path
)import package.foo
,import package.bar
undimport package.baz
wird alle Arbeit.pkg_resources.declare_namespace(__name__)
wurde nicht aktualisiert, um implizite Namespace-Pakete einzuschließen.quelle
namespace_packages
Option verwenden? Und das__import__('pkg_resources').declare_namespace(__name__)
Ding?namespace_packages=['package']
in dersetup.py
?namespace_packages=['package']
wird setup.py einnamespace_packages.txt
im EGG-INFO hinzufügen . Ich kenne die Auswirkungen immer noch nicht…pkg_resources.declare_namespace
overpkgutil.extend_path
ist, dass es weiterhin überwachtsys.path
. Auf diese Weise könnensys.path
Pakete im Namespace in diesem neuen Pfadelement weiterhin geladen werden, wenn ein neues Element hinzugefügt wird, nachdem ein Paket im Namespace zum ersten Mal geladen wurde. (Ein Vorteil der Verwendung von__import__('pkg_resources')
Overimport pkg_resources
ist, dass Sie nichtpkg_resources
als ausgesetzt werdenmy_namespace_pkg.pkg_resources
.)sys.path
. Beisys.path
Änderungen wird überprüft, ob sich dies auf__path__
einen Namespace auswirkt. Wenn dies der Fall ist, werden diese__path__
Eigenschaften aktualisiert .Es gibt ein Standardmodul namens pkgutil , mit dem Sie Module an einen bestimmten Namespace anhängen können.
Mit der von Ihnen angegebenen Verzeichnisstruktur:
Sie sollten diese beiden Zeilen in beide
Package-1/namespace/__init__.py
undPackage-2/namespace/__init__.py
(*) einfügen:(* da - es sei denn, Sie geben eine Abhängigkeit zwischen ihnen an - Sie nicht wissen, welche von ihnen zuerst erkannt werden - siehe PEP 420 für weitere Informationen)
Wie die Dokumentation sagt:
Von nun an sollten Sie in der Lage sein, diese beiden Pakete unabhängig voneinander zu verteilen.
quelle
__import__
wird dies in diesem Fall als schlechter Stil angesehen, da er leicht durch eine einfache Importanweisung ersetzt werden kann. Genauer gesagt ist pkg_resources eine nicht standardmäßige Bibliothek. Es wird mit Setuptools geliefert, das ist also kein Problem. Schnelles Googeln zeigt, dass pkgutil in 2.5 eingeführt wurde und pkg_resources älter ist. Trotzdem ist pkgutil eine offiziell anerkannte Lösung. Die Aufnahme von pkg_resources wurde in PEP 365 tatsächlich abgelehnt.Package-1/namespace/__init__.py
undPackage-2/namespace/__init__.py
vorausgesetzt, wir wissen nicht, welches Paketverzeichnis zuerst aufgeführt ist?Dieser Abschnitt sollte ziemlich selbsterklärend sein.
Kurz gesagt, geben Sie den Namespace-Code ein
__init__.py
, aktualisieren Sie ihnsetup.py
, um einen Namespace zu deklarieren, und Sie können loslegen.quelle
Dies ist eine alte Frage, aber jemand hat kürzlich in meinem Blog kommentiert, dass mein Beitrag über Namespace-Pakete immer noch relevant ist. Daher dachte ich, ich würde hier darauf verlinken, da er ein praktisches Beispiel dafür liefert, wie es funktioniert:
https://web.archive.org/web/20150425043954/http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb
Dieser Link zu diesem Artikel enthält die wichtigsten Informationen zu den Vorgängen:
http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package
Der
__import__("pkg_resources").declare_namespace(__name__)
Trick ist, die Verwaltung von Plugins in TiddlyWeb so ziemlich voranzutreiben und scheint bisher zu funktionieren.quelle
Sie haben Ihre Python-Namespace-Konzepte von hinten nach vorne. In Python ist es nicht möglich, Pakete in Module einzufügen. Pakete enthalten Module, nicht umgekehrt.
Ein Python-Paket ist einfach ein Ordner, der eine
__init__.py
Datei enthält. Ein Modul ist eine andere Datei in einem Paket (oder direkt auf demPYTHONPATH
), die eine.py
Erweiterung hat. In Ihrem Beispiel haben Sie also zwei Pakete, aber keine Module definiert. Wenn Sie bedenken, dass ein Paket ein Dateisystemordner und ein Modul eine Datei ist, sehen Sie, warum Pakete Module enthalten und nicht umgekehrt.In Ihrem Beispiel können Sie also davon ausgehen, dass Paket 1 und Paket 2 Ordner im Dateisystem sind, die Sie in den Python-Pfad eingefügt haben:
Sie haben jetzt ein Paket
namespace
mit zwei Modulenmodule1
undmodule2
. und wenn Sie keinen guten Grund haben, sollten Sie die Module wahrscheinlich in den Ordner legen und nur diesen auf dem Python-Pfad wie folgt haben:quelle
zope.x
wo eine Reihe verwandter Pakete als separate Downloads veröffentlicht werden.