Nachdem ich bereits Flat-Pakete verwendet hatte, hatte ich das Problem mit verschachtelten Paketen nicht erwartet. Hier ist…
Verzeichnislayout
dir
|
+-- test.py
|
+-- package
|
+-- __init__.py
|
+-- subpackage
|
+-- __init__.py
|
+-- module.py
Inhalt von init .py
Beide package/__init__.py
und package/subpackage/__init__.py
sind leer.
Inhalt von module.py
# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...
Inhalt von test.py
(3 Versionen)
Version 1
# file test.py
from package.subpackage.module import *
print attribute1 # OK
Das ist die schlechte und unsichere Art, Dinge zu importieren (alles in großen Mengen importieren), aber es funktioniert.
Version 2
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1
Eine sicherere Möglichkeit, Artikel für Artikel zu importieren, aber dies schlägt fehl. Python möchte dies nicht: schlägt mit der Meldung fehl: "Kein Modul mit dem Namen Modul". Jedoch …
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here
… Sagt <module 'package.subpackage.module' from '...'>
. Das ist also ein Modul, aber das ist kein Modul / -P 8-O ... ähm
Version 3
# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK
Dieser funktioniert. Sie sind also gezwungen, entweder ständig das Overkill-Präfix zu verwenden oder den unsicheren Weg wie in Version 1 zu verwenden, und von Python nicht zugelassen, den sicheren praktischen Weg zu verwenden? Der bessere Weg, der sicher ist und unnötiges langes Präfix vermeidet, ist der einzige, den Python ablehnt? Liegt es daran, dass es liebt import *
oder dass es überlange Präfixe liebt (was nicht dazu beiträgt, diese Praxis durchzusetzen)?
Entschuldigen Sie die harten Worte, aber das sind zwei Tage, an denen ich versuche, dieses dumme Verhalten zu umgehen. Wenn ich mich nicht irgendwo völlig geirrt habe, habe ich das Gefühl, dass etwas in Pythons Modell von Paketen und Unterpaketen wirklich kaputt ist.
Anmerkungen
- Ich möchte mich nicht auf
sys.path
globale Nebenwirkungen verlassen , um globale Nebenwirkungen zu vermeiden, und auch nicht auf*.pth
Dateien, die nur eine andere Möglichkeit sind,sys.path
mit denselben globalen Effekten zu spielen . Damit die Lösung sauber ist, muss sie nur lokal sein. Entweder ist Python in der Lage, Unterpakete zu verarbeiten, oder auch nicht, aber es sollte nicht erforderlich sein, mit der globalen Konfiguration zu spielen, um lokale Inhalte verarbeiten zu können. - Ich habe auch versucht, Importe zu verwenden
package/subpackage/__init__.py
, aber es hat nichts gelöst, es macht dasselbe und beschwert sich, dasssubpackage
es kein bekanntes Modul ist, während esprint subpackage
sagt , dass es ein Modul ist (wieder seltsames Verhalten).
Vielleicht bin ich völlig falsch hart (die Option, die ich bevorzugen würde), aber das macht mich sehr enttäuscht über Python.
Gibt es einen anderen bekannten Weg neben den drei, die ich versucht habe? Etwas, von dem ich nichts weiß?
(Seufzer)
-----% <----- edit ----->% -----
Fazit bisher (nach den Kommentaren der Leute)
In Python gibt es nichts Besseres als ein echtes Unterpaket, da alle Paketreferenzen nur auf ein globales Wörterbuch verweisen. Dies bedeutet, dass es kein lokales Wörterbuch gibt, was bedeutet, dass es keine Möglichkeit gibt, lokale Paketreferenzen zu verwalten.
Sie müssen entweder das vollständige Präfix oder das kurze Präfix oder den Alias verwenden. Wie in:
Vollständige Präfixversion
from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)
Kurze Präfixversion (aber wiederholtes Präfix)
from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place
Oder eine Variation der oben genannten.
from package.subpackage import module as m
use_of (m.attribute1)
# `m` is a shorter prefix, but you could as well
# define a more meaningful name after the context
Faktorisierte Version
Wenn es Ihnen nichts ausmacht, mehrere Entitäten gleichzeitig in einem Stapel zu importieren, können Sie:
from package.subpackage.module import attribute1, attribute2
# and etc.
Nicht in meinem ersten Lieblingsgeschmack (ich bevorzuge eine Importanweisung pro importierter Entität), aber möglicherweise die, die ich persönlich bevorzugen werde.
Update (14.09.2012):
Schließlich scheint es in der Praxis in Ordnung zu sein, außer mit einem Kommentar zum Layout. Anstelle der oben genannten habe ich verwendet:
from package.subpackage.module import (
attribute1,
attribute2,
attribute3,
...) # and etc.
__all__
Variable hinzufügen , die eine Liste der Namen enthält, die beim Sternimport exportiert werden sollen. edit: Okay, beim Lesen der BrenBarn-Antwort habe ich verstanden, was du meinst.Antworten:
Sie scheinen falsch zu verstehen, wie
import
nach Modulen gesucht wird. Wenn Sie eine Importanweisung verwenden, wird immer der tatsächliche Modulpfad (und / odersys.modules
) durchsucht . es macht keinen Gebrauch von Modul machen Objekte im lokalen Namespace, der wegen der früheren Einfuhren existieren. Wenn Sie das tun:In der zweiten Zeile wird nach einem aufgerufenen Paket gesucht
package.subpackage
undmodule
aus diesem Paket importiert . Diese Zeile hat keine Auswirkung auf die dritte Zeile. Die dritte Zeile sucht nur nach einem aufgerufenen Modulmodule
und findet keines. Das aufgerufene Objekt,module
das Sie aus der obigen Zeile erhalten haben, wird nicht "wiederverwendet" .Mit anderen Worten
from someModule import ...
bedeutet nicht "von dem Modul namens someModule, das ich zuvor importiert habe ...", sondern "von dem Modul namens someModule, das Sie auf sys.path finden ...". Es gibt keine Möglichkeit, den Pfad eines Moduls "inkrementell" aufzubauen, indem die Pakete importiert werden, die dazu führen. Sie müssen sich beim Importieren immer auf den gesamten Modulnamen beziehen.Es ist nicht klar, was Sie erreichen wollen. Wenn Sie nur das bestimmte Objektattribut1 importieren möchten, tun Sie es einfach
from package.subpackage.module import attribute1
und fertig. Sie müssen sich keine Gedanken mehr darüber machen, wie langepackage.subpackage.module
Sie den gewünschten Namen importiert haben.Wenn Sie noch Zugriff haben später andere Namen auf das Modul zugreifen möchten, dann können Sie tun
from package.subpackage import module
und wie Sie Sie dann tun können , gesehen habenmodule.attribute1
und so weiter , so viel wie Sie möchten.Wenn Sie beides möchten - das heißt, wenn Sie
attribute1
direkt zugänglich sein möchten und Siemodule
zugänglich sein möchten , führen Sie einfach beide oben genannten Schritte aus:Wenn Sie nicht
package.subpackage
einmal zweimal tippen möchten, können Sie einfach manuell einen lokalen Verweis auf Attribut1 erstellen:quelle
module.attribute1
ist etwas , über das ich nachgedacht habe, aber ich denke, es gäbe eine Möglichkeit, die Notwendigkeit eines Präfixes überall zu vermeiden. Ich muss also entweder überall ein Präfix verwenden oder einen lokalen Alias erstellen und den Namen wiederholen. Nicht der Stil, den ich erwartet hatte, aber wenn es keinen Weg gibt (schließlich bin ich an Ada gewöhnt, was mit seinen Umbenennungserklärungen etwas Ähnliches erfordert).Der Grund, warum # 2 fehlschlägt, ist, dass
sys.modules['module']
es keine gibt (die Importroutine hat einen eigenen Bereich und kann denmodule
lokalen Namen nicht sehen ) und es keinmodule
Modul oder Paket auf der Festplatte gibt. Beachten Sie, dass Sie mehrere importierte Namen durch Kommas trennen können.Ebenfalls:
quelle
sys.modules['name']
den ich bis jetzt nicht kannte, ließ mich denken, dass ich Angst hatte (und BrenBarn bestätigt): Es gibt nichts Schöneres als echte Unterpakete in Python.sys.modules
Wie der Name schon sagt, ist es global, und wenn alle Verweise auf Module davon abhängen, gibt es nichts Besseres als einen lokalen Verweis auf ein Modul (möglicherweise mit Python 3.x?).import
in # 2 generiert eine lokale Referenz, an diepackage.subpackage.module
gebunden werden sollmodule
.Wenn Sie nur versuchen, attribute1 in Ihrem globalen Namespace abzurufen, scheint Version 3 in Ordnung zu sein. Warum ist es Overkill-Präfix?
In Version 2 anstelle von
du kannst tun
quelle
attribute1 = module.attribute1
wiederholt nur den Namen ohne Mehrwert. Ich weiß, dass es funktioniert, aber ich mag diesen Stil nicht (was nicht bedeutet, dass ich Ihre Antwort nicht mag).