2009-11-04 8 views
110

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,Wie erstelle ich ein Namespace-Paket in Python?

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

der Endanwender kann import namespace.module1 und import namespace.module2.

Wie kann ein Namespace-Paket am besten definiert werden, sodass mehr als ein Python-Produkt Module in diesem Namespace definieren kann?

+3

Es sieht für mich so aus, als wären Modul1 und Modul2 eigentlich Unterpakete statt Module. Wie ich es verstehe, ist ein Modul im Grunde eine einzige Datei. Vielleicht würden subpkg1 und subpkg2 mehr Sinn machen als Namen? – Alan

Antwort

70

Es gibt ein Standardmodul, genannt pkgutil, mit dem Sie können ‚append‘ Module zu einem bestimmten Namespace.

Mit der Verzeichnisstruktur Sie zur Verfügung gestellt haben:

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

Sie sollten sowohl Package-1/namespace/__init__.py und Package-2/namespace/__init__.py (*), diese beiden Linien setzen: seit

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

(* -Außer Sie angeben, ein Abhängigkeit zwischen ihnen - Sie wissen nicht, welche von ihnen zuerst erkannt wird - siehe PEP 420 für weitere Informationen)

Wie die documentation sagt:

Diese __path__ alle Unterverzeichnisse von Verzeichnissen auf sys.path nach dem Paket mit dem Namen auf der Verpackung des hinzufügen.

Von nun an sollten Sie in der Lage sein, diese beiden Pakete unabhängig voneinander zu verteilen.

+15

Was sind die Vor- und Nachteile der Verwendung dieser im Vergleich zu __import __ ('pkg_resources'). Declare_namespace (__ name__)? – joeforker

+13

Zuerst wird "__import__" 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 kommt mit setuptools, also ist das kein Problem. Quick googling zeigt, dass pkgutil in 2.5 und pkg_resources bereits davor eingeführt wurde. Dennoch ist Pkgutil eine offiziell anerkannte Lösung. pkg_resources Aufnahme wurde tatsächlich in PEP 365 abgelehnt. –

+0

Ihre Funktionalität ist wahrscheinlich die gleiche, obwohl zope.interface beide in ihrem '__init __. py' verwendet. –

-8

Sie haben Ihre Python-Namespace-Konzepte von vorne nach hinten, es ist in Python nicht möglich, Pakete in Module zu setzen. Pakete enthalten Module nicht umgekehrt.

Ein Python-Paket ist einfach ein Ordner mit einer __init__.py Datei. Ein Modul ist eine beliebige andere Datei in einem Paket (oder direkt auf der PYTHONPATH), die eine .py Erweiterung hat. In Ihrem Beispiel haben Sie also zwei Pakete, aber keine Module definiert. Wenn Sie in Betracht ziehen, dass ein Paket ein Dateisystemordner und ein Modul eine Datei ist, sehen Sie, warum Pakete Module enthalten und nicht umgekehrt.

So in Ihrem Beispiel unter der Annahme, Package-1 und Package-2 sind Ordner auf dem Dateisystem, das Sie auf dem Python-Pfad gesetzt haben, können Sie folgende Voraussetzungen erfüllt sein:

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

Sie haben jetzt ein Paket namespace mit zwei Module module1 und module2. und es sei denn, Sie haben einen guten Grund sollten Sie wahrscheinlich die Module im Ordner abgelegt und nur, dass auf dem Python-Pfad wie unten:

Package-1/ 
    namespace/ 
    __init__.py 
    module1.py 
    module2.py 
+0

Ich spreche über Dinge wie 'zope.x', wo eine Reihe von verwandten Paketen als separate Downloads veröffentlicht werden. – joeforker

+0

Ok, aber was ist der Effekt, den du erreichen willst? Wenn die Ordner, die zusammengehörige Pakete enthalten, alle auf dem PYTHONPATH gefunden werden, wird der Python-Interpreter sie ohne zusätzliche Anstrengung für Sie finden. –

+5

Wenn Sie PYTHONPATH sowohl Paket-1 als auch Paket-2 hinzufügen, wird nur Paket-1/Namespace/von Python erkannt. –

5

This section should be pretty self-explanatory.

Kurz gesagt, stellen Sie den Namespace Code in __init__.py, aktualisieren setup.py einen Namespace zu deklarieren, und Sie sind frei zu gehen.

+6

Sie sollten immer den relevanten Teil eines Links angeben, für den Fall, dass der betreffende Link nicht mehr funktioniert. –

3

Dies ist eine alte Frage, aber jemand vor kurzem auf meinem Blog kommentiert, dass mein Posting über Namespace-Pakete noch relevant war, dachte so würde ich auf sie verwiesen wird hier, wie es ein praktisches Beispiel dafür, wie sieht, um es gehen:

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

, die für die Haupt Eingeweide zu diesem Artikel verknüpft, was los ist:

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

der __import__("pkg_resources").declare_namespace(__name__) Trick ist so ziemlich treibt die Verwaltung von Plugins in TiddlyWeb und scheint bis jetzt zu funktionieren.

40

TL; DR:

auf Python 3.3 Sie setzen nicht alles tun, nur keine __init__.py in Ihren Verzeichnissen Namespace-Paket und es wird funktionieren nur. Wählen Sie vor Version 3.3 die pkgutil.extend_path()-Lösung über die pkg_resources.declare_namespace(), da diese zukunftssicher und bereits mit impliziten Namespacepaketen kompatibel ist.


Python 3.3 führt implizite Namespace-Pakete, PEP 420 sehen.

Dies bedeutet, dass es nun drei Arten von Objekten sind, die von einer import foo erstellt werden können:

  • Ein Modul durch eine Datei foo.py dargestellt
  • Ein regelmäßiges Paket von einem Verzeichnis dargestellt foo eine __init__.py Datei enthält,
  • Ein Namespace-Paket,
  • durch ein oder mehrere Verzeichnisse foo ohne __init__.py Dateien dargestellt

Pakete sind auch Module, aber hier meine ich "Nicht-Paket-Modul", wenn ich "Modul" sage.

Zuerst scannt sys.path für ein Modul oder ein reguläres Paket. Wenn es erfolgreich ist, hört es auf zu suchen und erstellt und initialisiert das Modul oder Paket. Wenn kein Modul oder reguläres Paket gefunden wurde, aber mindestens ein Verzeichnis gefunden wurde, wird ein Namespacepaket erstellt und initialisiert.

Module und reguläre Pakete haben __file__ auf die .py Datei festgelegt, aus der sie erstellt wurden. Reguläre und Namespacepakete haben __path__ auf das Verzeichnis oder die Verzeichnisse festgelegt, aus denen sie erstellt wurden.

Wenn Sie import foo.bar tun, die oben Suche geschieht zuerst für foo, dann, wenn ein Paket gefunden wurde, die Suche nach bar mit foo.__path__ als Suchpfad getan statt sys.path. Wenn foo.bar gefunden wird, werden foo und foo.bar erstellt und initialisiert.

Wie also mischen sich reguläre Pakete und Namespacepakete? Normalerweise nicht, aber die alte pkgutil explizite Namespace-Paketmethode wurde um implizite Namespacepakete erweitert.

Wenn Sie ein vorhandenes reguläres Paket, das ein __init__.py so hat:

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

... das Vermächtnis Verhalten andere regelmäßig Pakete auf dem gesuchten Weg zu seinem __path__ hinzuzufügen. Aber in Python 3.3 fügt es auch Namespacepakete hinzu.

So können Sie die folgende Verzeichnisstruktur haben:

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

... und solange die beiden __init__.py haben die extend_path Linien (und path1, path2 und path3 sind in Ihrem sys.path) import package.foo, import package.bar und import package.baz wird alles funktionieren.

pkg_resources.declare_namespace(__name__) wurde nicht aktualisiert, um implizite Namespacepakete einzuschließen.

+2

Was ist mit setuptools? Muss ich die Option 'namespace_packages' verwenden? Und das ['__import__ ('pkg_resources') .declare_namespace (__name__)'] (http://setuptools.readthedocs.io/en/latest/setuptools.html#namespace-packages) was? –

+3

Soll ich 'namespace_packages = ['package']' in 'setup.py' hinzufügen? –

+0

@laurentlaport Gute Frage! Wenn Sie auf Python 3.3+ sind, hoffe ich nicht, aber bitte experimentieren Sie und kommen Sie mit einer Antwort zurück. ;-) Ich habe http://setuptools.readthedocs.io/en/latest/setuptools.html#namespace-packages gelesen, aber es ist nicht klar, ob es sich um eine ältere Dokumentation handelt, die nicht aktualisiert wurde oder ob sie noch gültig ist. – clacke