Ich war hier:
- http://www.python.org/dev/peps/pep-0328/
- http://docs.python.org/2/tutorial/modules.html#packages
- Python-Pakete: relative Importe
- Beispielcode für den relativen Python-Import funktioniert nicht
- Ultimative Antwort auf relative Python-Importe
- Relative Importe in Python
- Python: Relativen Import deaktivieren
und viele URLs, die ich nicht kopiert habe, einige auf SO, andere auf anderen Websites, als ich dachte, ich hätte die Lösung schnell.
Die immer wiederkehrende Frage lautet: Wie löse ich unter Windows 7, 32-Bit-Python 2.7.3, die Meldung "Versuchter relativer Import in Nicht-Paket"? Ich habe eine genaue Replik des Pakets auf pep-0328 erstellt:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
Die Importe wurden von der Konsole aus durchgeführt.
Ich habe Funktionen namens Spam und Eier in den entsprechenden Modulen erstellt. Natürlich hat es nicht funktioniert. Die Antwort ist anscheinend in der 4. URL, die ich aufgelistet habe, aber es sind alles Alumni für mich. Es gab diese Antwort auf eine der URLs, die ich besucht habe:
Relative Importe verwenden das Namensattribut eines Moduls, um die Position dieses Moduls in der Pakethierarchie zu bestimmen. Wenn der Name des Moduls keine Paketinformationen enthält (z. B. auf 'main' gesetzt), werden relative Importe so aufgelöst, als wäre das Modul ein Modul der obersten Ebene, unabhängig davon, wo sich das Modul tatsächlich im Dateisystem befindet.
Die obige Antwort sieht vielversprechend aus, aber für mich sind alles Hieroglyphen. Also meine Frage, wie kann ich Python dazu bringen, nicht zu mir zurückzukehren "Versuchter relativer Import in Nicht-Paket"? hat eine Antwort, die angeblich -m beinhaltet.
Kann mir bitte jemand sagen, warum Python diese Fehlermeldung gibt, was es unter "Nicht-Paket" versteht, warum und wie Sie ein "Paket" definieren und die genaue Antwort so formuliert ist, dass ein Kindergärtner sie leicht verstehen kann .
quelle
def spam(): pass
, moduleA.py hatdef eggs(): pass
. Ich habe versucht, ein paar Befehle "von etwas importieren" auszuführen, aber sie haben nicht funktioniert. Siehe auch pep-0328.from .something import something
im interaktiven Interpreter zu tun , funktioniert dies nicht. Relative Importe können nur innerhalb von Modulen verwendet werden, nicht interaktiv.Antworten:
Skript vs. Modul
Hier ist eine Erklärung. Die Kurzversion ist, dass es einen großen Unterschied zwischen dem direkten Ausführen einer Python-Datei und dem Importieren dieser Datei von einem anderen Ort gibt. Nur zu wissen, in welchem Verzeichnis sich eine Datei befindet, bestimmt nicht, in welchem Paket Python sich befindet. Dies hängt außerdem davon ab, wie Sie die Datei in Python laden (durch Ausführen oder Importieren).
Es gibt zwei Möglichkeiten, eine Python-Datei zu laden: als Skript der obersten Ebene oder als Modul. Eine Datei wird als Skript der obersten Ebene geladen, wenn Sie sie direkt ausführen, z. B. durch Eingabe
python myfile.py
in der Befehlszeile. Es wird als Modul geladen, wenn Sie dies tunpython -m myfile
, oder wenn es geladen wird, wenn eineimport
Anweisung in einer anderen Datei gefunden wird. Es kann immer nur ein Skript der obersten Ebene vorhanden sein. Das Skript der obersten Ebene ist die Python-Datei, die Sie ausgeführt haben, um die Dinge zu starten.Benennung
Wenn eine Datei geladen wird, erhält sie einen Namen (der in ihrem
__name__
Attribut gespeichert ist ). Wenn es als Skript der obersten Ebene geladen wurde, lautet sein Name__main__
. Wenn es als Modul geladen wurde, ist sein Name der Dateiname, vor dem die Namen aller Pakete / Unterpakete stehen, zu denen es gehört, getrennt durch Punkte.Also zum Beispiel in Ihrem Beispiel:
Wenn Sie importiert haben
moduleX
(Hinweis: importiert , nicht direkt ausgeführt), lautet der Namepackage.subpackage1.moduleX
. Wenn Sie importierenmoduleA
, wäre der Namepackage.moduleA
. Wenn Sie jedoch direktmoduleX
über die Befehlszeile ausgeführt werden, lautet der Name stattdessen__main__
, und wenn Sie direktmoduleA
über die Befehlszeile ausgeführt werden, lautet der Name__main__
. Wenn ein Modul als Skript der obersten Ebene ausgeführt wird, verliert es seinen normalen Namen und stattdessen seinen Namen__main__
.Zugriff auf ein Modul NICHT über das enthaltene Paket
Es gibt eine zusätzliche Falte: Der Name des Moduls hängt davon ab, ob es "direkt" aus dem Verzeichnis, in dem es sich befindet, oder über ein Paket importiert wurde. Dies macht nur dann einen Unterschied, wenn Sie Python in einem Verzeichnis ausführen und versuchen, eine Datei in dasselbe Verzeichnis (oder ein Unterverzeichnis davon) zu importieren. Wenn Sie beispielsweise den Python-Interpreter im Verzeichnis starten
package/subpackage1
und dies dann tunimport moduleX
, lautet der NamemoduleX
nurmoduleX
und nichtpackage.subpackage1.moduleX
. Dies liegt daran, dass Python beim Start das aktuelle Verzeichnis zu seinem Suchpfad hinzufügt. Wenn das zu importierende Modul im aktuellen Verzeichnis gefunden wird, weiß es nicht, dass dieses Verzeichnis Teil eines Pakets ist, und die Paketinformationen werden nicht Teil des Modulnamens.Ein Sonderfall ist, wenn Sie den Interpreter interaktiv ausführen (z. B. einfach
python
Python-Code eingeben und sofort eingeben). In diesem Fall lautet der Name dieser interaktiven Sitzung__main__
.Hier ist das Entscheidende für Ihre Fehlermeldung: Wenn der Name eines Moduls keine Punkte enthält, wird er nicht als Teil eines Pakets betrachtet . Es spielt keine Rolle, wo sich die Datei tatsächlich auf der Festplatte befindet. Alles, was zählt, ist der Name und der Name hängt davon ab, wie Sie ihn geladen haben.
Schauen Sie sich nun das Zitat an, das Sie in Ihre Frage aufgenommen haben:
Relative Importe ...
Relative Importe verwenden den Namen des Moduls, um zu bestimmen, wo es sich in einem Paket befindet. Wenn Sie einen relativen Import wie verwenden
from .. import foo
, geben die Punkte an, dass einige Ebenen in der Pakethierarchie erhöht werden sollen. Wenn der Name Ihres aktuellen Moduls beispielsweise lautetpackage.subpackage1.moduleX
,..moduleA
würde dies bedeutenpackage.moduleA
. Damit einfrom .. import
Modul funktioniert, muss der Name des Moduls mindestens so viele Punkte enthalten, wie in derimport
Anweisung enthalten sind.... sind nur in einem Paket relativ
Wenn der Name Ihres Moduls jedoch lautet
__main__
, wird er nicht als in einem Paket enthalten betrachtet. Sein Name hat keine Punkte und daher können Sie keine darin enthaltenenfrom .. import
Anweisungen verwenden. Wenn Sie dies versuchen, wird der Fehler "Relativer Import in Nicht-Paket" angezeigt.Skripte können nicht relativ importiert werden
Was Sie wahrscheinlich getan haben, ist, dass Sie versucht haben,
moduleX
über die Befehlszeile oder ähnliches auszuführen . Als Sie dies getan haben, wurde sein Name auf gesetzt__main__
, was bedeutet, dass relative Importe darin fehlschlagen, da sein Name nicht anzeigt, dass es sich in einem Paket befindet. Beachten Sie, dass dies auch passiert, wenn Sie Python aus demselben Verzeichnis ausführen, in dem sich ein Modul befindet, und dann versuchen, dieses Modul zu importieren, da Python das Modul wie oben beschrieben "zu früh" im aktuellen Verzeichnis findet, ohne es zu bemerken Teil eines Pakets.Denken Sie auch daran, dass beim Ausführen des interaktiven Interpreters immer der "Name" dieser interaktiven Sitzung lautet
__main__
. Daher können Sie keine relativen Importe direkt aus einer interaktiven Sitzung durchführen . Relative Importe sind nur zur Verwendung in Moduldateien vorgesehen.Zwei Lösungen:
Wenn Sie wirklich
moduleX
direkt ausgeführt werden möchten, es aber dennoch als Teil eines Pakets betrachtet werden sollen, können Sie dies tunpython -m package.subpackage1.moduleX
. Das-m
weist Python an, es als Modul zu laden, nicht als Skript der obersten Ebene.Oder vielleicht möchten Sie nicht wirklich ausführen
moduleX
, sondern nur ein anderes Skript ausführenmyfile.py
, das beispielsweise Funktionen verwendetmoduleX
. Wenn dies der Fall ist, legen Sie es an einermyfile.py
anderen Stelle ab - nicht impackage
Verzeichnis - und führen Sie es aus. Wennmyfile.py
Sie Dinge wie tunfrom package.moduleA import spam
, wird es gut funktionieren.Anmerkungen
Für jede dieser Lösungen muss auf das Paketverzeichnis (
package
in Ihrem Beispiel) über den Suchpfad des Python-Moduls (sys.path
) zugegriffen werden können . Ist dies nicht der Fall, können Sie nichts im Paket zuverlässig verwenden.Seit Python 2.6 wird der "Name" des Moduls für Zwecke der Paketauflösung nicht nur durch seine
__name__
Attribute, sondern auch durch das__package__
Attribut bestimmt. Deshalb vermeide ich es, das explizite Symbol__name__
zu verwenden, um auf den "Namen" des Moduls zu verweisen. Da Python 2.6 ein Modul der „name“ ist effektiv__package__ + '.' + __name__
, oder einfach nur ,__name__
wenn__package__
istNone
.)quelle
Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the "relative-import in non-package" error.
Das ist grundsätzlich beunruhigend. Was ist so schwierig am Betrachten des aktuellen Verzeichnisses? Python sollte dazu in der Lage sein. Ist das in Version 3x behoben?__package__ = 'package.subpackage1'
oder dergleichen tun . Dann nur die Datei wird immer ein Teil dieses Paket betrachtet werden , auch wenn direkt ausgeführt werden . Wenn Sie weitere Fragen zu haben__package__
, möchten Sie möglicherweise eine separate Frage stellen, da wir hier das Problem Ihrer ursprünglichen Frage lösen.__name__
undsys.path
. Genauer gesagt, mitpython -m pkg.mod
,__name__
festgelegt ist__main__
, nichtpkg.mod
; relative Importe werden__package__
nicht__name__
in diesem Fall , sondern mit aufgelöst . Außerdem fügt Pythonsys.path
beim Ausführen das Verzeichnis des Skripts und nicht das aktuelle Verzeichnis hinzupython path/to/script.py
. Es fügt das aktuelle Verzeichnis hinzu,sys.path
wenn die meisten anderen Methoden ausgeführt werden, einschließlichpython -m pkg.mod
.Dies ist wirklich ein Problem in Python. Der Grund für die Verwirrung ist, dass Menschen fälschlicherweise den relativen Import als relativen Pfad betrachten, was nicht der Fall ist.
Zum Beispiel, wenn Sie in faa.py schreiben :
Dies hat nur einen Sinn , wenn faa.py wurde identifiziert und geladen von Python, die während der Ausführung, als Teil eines Pakets. In diesem Fall wäre der Name des Moduls für faa.py beispielsweise some_packagename.faa . Wenn die Datei geladen wurde, nur weil sie sich im aktuellen Verzeichnis befindet, wenn Python ausgeführt wird, verweist ihr Name nicht auf ein Paket und der relative Import schlägt möglicherweise fehl.
Eine einfache Lösung zum Verweisen auf Module im aktuellen Verzeichnis besteht darin, Folgendes zu verwenden:
quelle
from __future__ import absolute_import
und zwingen Sie den Benutzer, Ihren Code korrekt zu verwenden ... so dass Sie immer tun könnenfrom . import foo
Hier ist ein allgemeines Rezept, das als Beispiel geändert wurde und das ich derzeit für den Umgang mit Python-Bibliotheken verwende, die als Pakete geschrieben sind und voneinander abhängige Dateien enthalten, in denen ich Teile davon stückweise testen möchte. Nennen wir dies
lib.foo
und sagen wir, dasslib.fileA
für Funktionenf1
undf2
undlib.fileB
für die Klasse Zugriff erforderlich istClass3
.Ich habe einige
print
Aufrufe beigefügt , um zu veranschaulichen, wie dies funktioniert. In der Praxis möchten Sie sie (und möglicherweise auch diefrom __future__ import print_function
Linie) entfernen .Dieses spezielle Beispiel ist zu einfach, um zu zeigen, wann wir wirklich einen Eintrag in einfügen müssen
sys.path
. (Siehe Lars 'Antwort für einen Fall, in dem wir es brauchen, wenn wir zwei oder mehr Ebenen von Paketverzeichnissen haben und dann verwendenos.path.dirname(os.path.dirname(__file__))
- aber es tut auch hier nicht wirklich weh .) Es ist auch sicher genug, dies ohne das zu tunif _i in sys.path
Prüfung. Wenn jedoch jede importierte Datei denselben Pfad einfügt, z. B. wenn beidefileA
undfileB
Dienstprogramme aus dem Paket importieren möchten, wirdsys.path
der Pfad häufig mit demselben Pfad überfüllt , sodass es schön ist, den Pfadif _i not in sys.path
in der Boilerplate zu haben.Die Idee hier ist folgende (und beachten Sie, dass diese alle in Python2.7 und Python 3.x gleich funktionieren):
Wenn es als
import lib
oderfrom lib import foo
als regulärer Paketimport aus normalem Code ausgeführt wird,__package
istlib
und__name__
istlib.foo
. Wir nehmen den ersten Codepfad, importieren aus.fileA
usw.Wenn ausgeführt als
python lib/foo.py
,__package__
wird Keine sein und__name__
wird sein__main__
.Wir nehmen den zweiten Codepfad. Das
lib
Verzeichnis befindet sich bereits,sys.path
sodass es nicht hinzugefügt werden muss. Wir importieren ausfileA
usw.Wenn im
lib
Verzeichnis als ausgeführtpython foo.py
, ist das Verhalten dasselbe wie in Fall 2.Bei Ausführung innerhalb des
lib
Verzeichnisses alspython -m foo
ähnelt das Verhalten den Fällen 2 und 3. Der Pfad zumlib
Verzeichnis befindet sich jedoch nicht insys.path
. Daher fügen wir ihn vor dem Import hinzu. Gleiches gilt, wenn wir Python ausführen und dannimport foo
.(Da
.
ist insys.path
, wissen wir nicht wirklich brauchen hier die absolute Version des Pfades hinzuzufügen. Dies ist , wo eine tiefes Paket Verschachtelung, wo wir tun wollenfrom ..otherlib.fileC import ...
, einen Unterschied macht. Wenn Sie das nicht tun, können Sie allesys.path
Manipulationen ganz weglassen .)Anmerkungen
Es gibt immer noch eine Eigenart. Wenn Sie diese ganze Sache von außen ausführen:
oder:
Das Verhalten hängt vom Inhalt von ab
lib/__init__.py
. Wenn das existiert und leer ist , ist alles in Ordnung:Aber wenn
lib/__init__.py
selbst importiert,routine
so dass esroutine.name
direkt als exportieren kannlib.name
, erhalten Sie:Das heißt, das Modul wird zweimal importiert, einmal über das Paket und dann erneut
__main__
, damit Ihrmain
Code ausgeführt wird. Python 3.6 und höher warnen davor:Die Warnung ist neu, das Warnverhalten jedoch nicht. Es ist Teil dessen, was manche als Doppelimportfalle bezeichnen . (Weitere Einzelheiten finden Sie in Ausgabe 27487. ) Nick Coghlan sagt:
Beachten Sie, dass wir hier zwar gegen diese Regel verstoßen, dies jedoch nur tun, wenn die zu ladende Datei nicht als Teil eines Pakets geladen wird. Unsere Änderung wurde speziell entwickelt, um den Zugriff auf andere Dateien in diesem Paket zu ermöglichen. (Und wie ich bereits erwähnt habe, sollten wir dies für einstufige Pakete wahrscheinlich überhaupt nicht tun.) Wenn wir besonders sauber sein möchten, können wir dies wie folgt umschreiben: z.
Das heißt, wir ändern
sys.path
lange genug, um unsere Importe zu erzielen, und setzen es dann wieder so ein, wie es war (Löschen einer Kopie von_i
genau dann, wenn wir eine Kopie von hinzugefügt haben_i
).quelle
Nachdem ich zusammen mit vielen anderen darüber nachgedacht hatte, stieß ich auf eine Notiz von Dorian B in diesem Artikel , die das spezifische Problem löste, das ich hatte, wo ich Module und Klassen für die Verwendung mit einem Webdienst entwickeln würde, aber ich möchte es auch sein Sie können sie beim Codieren mithilfe der Debugger-Funktionen in PyCharm testen. Um Tests in einer eigenständigen Klasse auszuführen, würde ich am Ende meiner Klassendatei Folgendes einfügen:
Wenn ich jedoch andere Klassen oder Module in denselben Ordner importieren wollte, musste ich alle meine Importanweisungen von der relativen Notation in lokale Referenzen ändern (dh den Punkt (.) entfernen). Nachdem ich Dorians Vorschlag gelesen hatte, versuchte ich es mit seinem ' Einzeiler 'und es hat funktioniert! Ich kann jetzt in PyCharm testen und meinen Testcode beibehalten, wenn ich die Klasse in einer anderen getesteten Klasse verwende oder wenn ich sie in meinem Webdienst verwende!
Die if-Anweisung prüft, ob dieses Modul als Hauptmodul ausgeführt wird oder ob es in einem anderen Modul verwendet wird, das als Hauptmodul getestet wird . Vielleicht ist dies offensichtlich, aber ich biete diesen Hinweis hier an, falls jemand anderes, der von den oben genannten relativen Importproblemen frustriert ist, davon Gebrauch machen kann.
quelle
Hier ist eine Lösung, die ich nicht empfehlen würde, die aber in einigen Situationen nützlich sein könnte, in denen Module einfach nicht generiert wurden:
quelle
Ich hatte ein ähnliches Problem, bei dem ich den Suchpfad des Python-Moduls nicht ändern wollte und ein Modul relativ aus einem Skript laden musste (trotz "Skripte können nicht relativ mit allen importiert werden"). wie BrenBarn oben ausführlich erläutert hat).
Also habe ich den folgenden Hack benutzt. Leider ist es darauf angewiesen,
imp
dass das Modul, das seit Version 3.4 veraltet ist, zugunsten von gelöscht wirdimportlib
. (Ist das auch mit möglichimportlib
? Ich weiß es nicht.) Trotzdem funktioniert der Hack vorerst.Beispiel für den Zugriff auf Mitglieder von
moduleX
insubpackage1
über ein Skript imsubpackage2
Ordner:Ein sauberer Ansatz scheint darin zu bestehen, den von Federico erwähnten sys.path zum Laden von Modulen zu ändern.
quelle
__name__
ändert sich abhängig davon, ob der betreffende Code im globalen Namespace oder als Teil eines importierten Moduls ausgeführt wird.Wenn der Code nicht im globalen Bereich ausgeführt
__name__
wird, lautet der Name des Moduls. Wenn im globalen Namensraum läuft - zum Beispiel, wenn Sie es in eine Konsole eingeben oder das Modul als Skript ausgeführt unter Verwendungpython.exe yourscriptnamehere.py
dann__name__
wird"__main__"
.Sie werden sehen, dass viel Python-Code
if __name__ == '__main__'
verwendet wird, um zu testen, ob der Code aus dem globalen Namespace ausgeführt wird. Auf diese Weise können Sie ein Modul verwenden, das gleichzeitig als Skript fungiert.Haben Sie versucht, diese Importe von der Konsole durchzuführen?
quelle
@ BrenBarns Antwort sagt alles, aber wenn du wie ich bist, kann es eine Weile dauern, bis du es verstehst. Hier ist mein Fall und wie die Antwort von @ BrenBarn darauf zutrifft, vielleicht hilft es Ihnen.
Der Fall
Verwenden Sie unser bekanntes Beispiel und fügen Sie hinzu, dass moduleX.py einen relativen Import zu ..moduleA hat. Angesichts der Tatsache, dass ich versucht habe, ein Testskript in das Verzeichnis subpackage1 zu schreiben, das moduleX importiert hat, aber dann den vom OP beschriebenen gefürchteten Fehler erhalten habe.
Lösung
Verschieben Sie das Testskript auf die gleiche Ebene wie package und importieren Sie package.subpackage1.moduleX
Erläuterung
Wie erläutert, werden relative Importe relativ zum aktuellen Namen durchgeführt. Wenn mein Testskript moduleX aus demselben Verzeichnis importiert, lautet der Modulname in moduleX moduleX. Wenn ein relativer Import auftritt, kann der Interpreter die Pakethierarchie nicht sichern, da sie sich bereits oben befindet
Wenn ich moduleX von oben importiere, lautet der Name in moduleX package.subpackage1.moduleX und der relative Import kann gefunden werden
quelle
Schrieb ein kleines Python-Paket an PyPi, das den Zuschauern dieser Frage helfen könnte. Das Paket dient als Problemumgehung, wenn Python-Dateien mit Importen, die Pakete der oberen Ebene enthalten, aus einem Paket / Projekt ausgeführt werden sollen, ohne sich direkt im Verzeichnis der importierenden Datei zu befinden. https://pypi.org/project/import-anywhere/
quelle
Damit Python nicht zu mir zurückkehrt "Versuchter relativer Import in Nicht-Paket". Paket/
init .py subpackage1 / init .py moduleX.py moduleY.py subpackage2 / init .py moduleZ.py moduleA.py
Dieser Fehler tritt nur auf, wenn Sie einen relativen Import auf die übergeordnete Datei anwenden. Zum Beispiel gibt die übergeordnete Datei bereits main zurück, nachdem Sie "print ( name )" in moduleA.py codiert haben. Diese Datei ist also bereits vorhanden mainEs kann kein übergeordnetes Paket weitergeben. Relative Importe sind in Dateien der Pakete subpackage1 und subpackage2 erforderlich. Sie können ".." verwenden, um auf das übergeordnete Verzeichnis oder Modul zu verweisen. Das übergeordnete Verzeichnis ist jedoch, wenn es bereits ein Paket der obersten Ebene ist, kann es nicht weiter über dieses übergeordnete Verzeichnis (Paket) hinausgehen. Solche Dateien, in denen Sie den relativen Import auf Eltern anwenden, können nur mit der Anwendung des absoluten Imports funktionieren. Wenn Sie ABSOLUTE IMPORT IN ELTERNPAKET verwenden, tritt KEIN FEHLER auf, da Python weiß, wer sich auf der obersten Ebene des Pakets befindet, selbst wenn sich Ihre Datei aufgrund des Konzepts von PYTHON PATH, das die oberste Ebene des Projekts definiert, in Unterpaketen befindet
quelle