Ich versuche, PEP 328 mit der folgenden Verzeichnisstruktur zu folgen :
pkg/
__init__.py
components/
core.py
__init__.py
tests/
core_test.py
__init__.py
In habe core_test.py
ich die folgende Importanweisung
from ..components.core import GameLoopEvents
Beim Ausführen wird jedoch der folgende Fehler angezeigt:
tests$ python core_test.py
Traceback (most recent call last):
File "core_test.py", line 3, in <module>
from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package
Beim Durchsuchen fand ich " relativer Pfad funktioniert nicht einmal mit __init__.py " und " Importiere ein Modul von einem relativen Pfad ", aber sie halfen nicht.
Fehlt mir hier etwas?
python
package
python-import
importerror
init
Skytreader
quelle
quelle
unittest
Projekten, daher schrieb ich dieses ziemlich erschöpfende Beispielprojekt , das die tiefe Verschachtelung von Modulen, relative und absolute Importe (wo die Arbeit funktioniert und nicht) sowie relative und absolute Referenzierung aus einem heraus behandelt Paket sowie Import von Klassen auf Einzel-, Doppel- und Paketebene. Hat mir geholfen, die Dinge richtig zu machen!no module named myimports.foo
wenn ich sie laufen lasse.cd
inPyImports
, und laufenpython -m unittest tests.test_abs
, zum Beispiel.Antworten:
Ja. Sie verwenden es nicht als Paket.
quelle
__init__.py
s ganz unten benötigen , und den__package__
Trick zum Ändern (unten von BrenBarn beschrieben), der erforderlich ist, um diese Importe für ausführbare Skripte zu ermöglichen (z. B. bei Verwendung eines shebang und./my_script.py
an der Unix-Shell zu tun ) wäre alles nützlich. Diese ganze Ausgabe war ziemlich schwierig für mich, eine präzise und verständliche Dokumentation zu finden oder zu finden.pkg
an dem Punkt außerhalb des Verzeichnisses befinden, an dem Sie diese Zeile über die CLI aufrufen. Dann sollte es wie erwartet funktionieren. Wenn Sie drinnen sindpkg
und anrufenpython -m tests.core_test
, funktioniert es nicht. Zumindest nicht für mich.__init__.py
Dateien enthalten, aber Sie erhalten immer wieder denValueError: Attempted relative import in non-package
Fehler. Ich würde irgendwo wirklich gutes Geld für jemanden bezahlen, um endlich im Klartext zu erklären, wie das alles funktioniert.Um die Antwort von Ignacio Vazquez-Abrams näher zu erläutern :
Der Python-Importmechanismus funktioniert relativ zur
__name__
aktuellen Datei. Wenn Sie eine Datei direkt ausführen, hat sie nicht den üblichen Namen, sondern"__main__"
den Namen. Relative Importe funktionieren also nicht.Sie können es, wie von Igancio vorgeschlagen, mit der
-m
Option ausführen . Wenn Sie einen Teil Ihres Pakets haben, der als Skript ausgeführt werden soll, können Sie das__package__
Attribut auch verwenden , um dieser Datei mitzuteilen, welchen Namen sie in der Pakethierarchie haben soll.Weitere Informationen finden Sie unter http://www.python.org/dev/peps/pep-0366/ .
quelle
python -m core_test
aus demtests
Unterverzeichnis heraus ausgeführt werden können - es muss vom übergeordneten Verzeichnis stammen oder Sie müssen das übergeordnete Element zum Pfad hinzufügen.__package__
damit sicherstellen, dass ausführbare Skriptdateien andere Module aus demselben Paket relativ importieren können. Es gibt keine Möglichkeit, relativ aus "dem gesamten System" zu importieren. Ich bin mir nicht mal sicher, warum Sie das tun möchten.__package__
Symbol auf "parent.child" gesetzt ist, können Sie "parent.other_child" importieren. Vielleicht habe ich es nicht so gut formuliert.script.py
im Paketpack.subpack
, dann Einstellung ist es__package__
zu waspack.subpack
Sie tun können ,from ..module import something
um zu importieren etwaspack.module
. Beachten Sie, dass Sie, wie in der Dokumentation angegeben, immer noch das Paket der obersten Ebene im Systempfad haben müssen. So funktioniert es bereits bei importierten Modulen. Das einzige , was__package__
tut , ist man dieses Verhalten als auch für direkt ausgeführte Skripte verwenden lassen.__package__
in dem Skript, das direkt ausgeführt wird, aber leider erhalte ich die folgende Fehlermeldung: "Übergeordnetes Modul 'xxx' nicht geladen, kann keinen relativen Import durchführen"Sie können
import components.core
direkt verwenden, wenn Sie das aktuelle Verzeichnis an Folgendes anhängensys.path
:quelle
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
Dies wird auch funktionierenfrom os import sys
sieht aus wie Betrug :)sys.path
- das übergeordnete Verzeichnis des Verzeichnisses, in dem sich die aktuelle Datei befindet.import sys, os.path as path
.import os; os.sys.path.append(os.path.dirname(os.path.abspath('.')))
. Dannimport components.core
funktioniert ein Straight für mich und importiert wie gewünscht aus dem übergeordneten Verzeichnis des Notebooks.Dies hängt davon ab, wie Sie Ihr Skript starten möchten.
Wenn Sie Ihren UnitTest auf klassische Weise über die Befehlszeile starten möchten, gilt Folgendes :
Da in diesem Fall 'Komponenten' und 'Tests' Geschwisterordner sind, können Sie das relative Modul entweder mit der Einfügemethode oder der Append- Methode des Moduls sys.path importieren . Etwas wie:
Andernfalls können Sie Ihr Skript mit dem Argument '-m' starten (beachten Sie, dass es sich in diesem Fall um ein Paket handelt und Sie daher nicht die Erweiterung '.py' angeben dürfen ).
In einem solchen Fall können Sie einfach den relativen Import verwenden, wie Sie es getan haben:
Sie können schließlich die beiden Ansätze mischen, sodass Ihr Skript unabhängig vom Namen funktioniert. Zum Beispiel:
quelle
python -m pdb myscript.py
, um die Debugging-Sitzung zu starten.import pdb; pdb.set_trace()
in den Code einfügen (Inline).insert
alsappend
? Das heißt,sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
Gehen Sie in core_test.py wie folgt vor:
quelle
Wenn Ihr Anwendungsfall für das Ausführen von Tests vorgesehen ist und dies der Fall ist, können Sie Folgendes tun. Anstatt Ihr Testskript so auszuführen,
python core_test.py
verwenden Sie ein Testframework wie zpytest
. Dann können Sie in der Befehlszeile eingebenDadurch werden die Tests in Ihrem Verzeichnis ausgeführt. Dies umgeht das Problem des
__name__
Seins__main__
, auf das @BrenBarn hingewiesen hat. Fügen Sie als Nächstes eine leere__init__.py
Datei in Ihr Testverzeichnis ein. Dadurch wird das Testverzeichnis Teil Ihres Pakets. Dann können Sie tunWenn Sie Ihr Testskript jedoch als Hauptprogramm ausführen, schlagen die Dinge erneut fehl. Verwenden Sie also einfach den Testläufer. Vielleicht funktioniert das auch mit anderen Testläufern wie,
nosetests
aber ich habe es nicht überprüft. Hoffe das hilft.quelle
Meine schnelle Lösung besteht darin, das Verzeichnis dem Pfad hinzuzufügen:
quelle
Problem ist mit Ihrer Testmethode,
du versuchtest
python core_test.py
Dann wird dieser Fehler angezeigt. ValueError: Relativer Importversuch in Nicht-Paket versucht
Grund: Sie testen Ihre Verpackung aus einer nicht verpackten Quelle.
Testen Sie also Ihr Modul aus der Paketquelle.
Wenn dies Ihre Projektstruktur ist,
cd pkg
oder von außerhalb pkg /
single,
.
wenn Sie aus einem Ordner im selben Verzeichnis importieren möchten. Fügen Sie für jeden Schritt zurück einen weiteren hinzu.im
how.py
falls Sie wie aus hello.py importieren möchten
quelle
from .. import how
Wie importieren Sie im Beispiel eine bestimmte Klasse / Methode aus der 'how'-Datei? Wenn ich das Äquivalent dazu mache,from ..how import foo
bekomme ich "einen relativen Importversuch über das Top-Level-Paket hinaus"Alter Faden. Ich fand heraus, dass das Hinzufügen eines
__all__= ['submodule', ...]
zur __init__.py- Datei und das anschließende Verwenden vonfrom <CURRENT_MODULE> import *
im Ziel gut funktioniert.quelle
Sie können
from pkg.components.core import GameLoopEvents
zum Beispiel pycharm verwenden. Das Folgende ist mein Projektstrukturbild. Ich importiere es einfach aus dem Root-Paket, dann funktioniert es:quelle
Wie Paolo sagte, haben wir zwei Aufrufmethoden:
Ein Unterschied zwischen ihnen ist die Zeichenfolge sys.path [0]. Da die Interpretation beim Importieren nach sys.path sucht , können wir Folgendes tun
tests/core_test.py
:Und danach können wir core_test.py mit anderen Methoden ausführen:
Beachten Sie, dass nur py36 getestet wurde.
quelle
Dieser Ansatz hat bei mir funktioniert und ist weniger überladen als einige Lösungen:
Das übergeordnete Verzeichnis befindet sich in meinem PYTHONPATH, und
__init__.py
im übergeordneten Verzeichnis und in diesem Verzeichnis befinden sich Dateien.Das Obige funktionierte immer in Python 2, aber Python 3 traf manchmal einen ImportError oder ModuleNotFoundError (letzteres ist neu in Python 3.6 und eine Unterklasse von ImportError), sodass die folgende Optimierung für mich sowohl in Python 2 als auch in Python 3 funktioniert:
quelle
Versuche dies
quelle
Wenn jemand nach einer Problemumgehung sucht, bin ich auf eine gestoßen. Hier ist ein bisschen Kontext. Ich wollte eine der Methoden testen, die ich in einer Datei habe. Wenn ich es von innen laufen lasse
es beklagte sich immer über die relativen Importe. Ich habe versucht, die oben genannten Lösungen anzuwenden, aber es hat nicht funktioniert, da es viele verschachtelte Dateien mit jeweils mehreren Importen gab.
Folgendes habe ich getan. Ich habe gerade einen Launcher erstellt, ein externes Programm, das die erforderlichen Methoden importiert und aufruft. Obwohl keine gute Lösung, funktioniert es.
quelle
Hier ist eine Möglichkeit, die alle verärgert, aber ziemlich gut funktioniert. In Testläufen:
Importieren Sie dann einfach die Komponenten wie gewohnt.
quelle
Dies ist sehr verwirrend, und wenn Sie IDE wie Pycharm verwenden, ist es etwas verwirrender. Was bei mir funktioniert hat: 1. Nehmen Sie Pycharm-Projekteinstellungen vor (wenn Sie Python von einem VE oder aus einem Python-Verzeichnis ausführen). 2. Die von Ihnen definierte Vorgehensweise ist nicht falsch. Manchmal funktioniert es mit der Importklasse folder1.file1
Wenn dies nicht funktioniert, verwenden Sie import folder1.file1. 3. Ihre Umgebungsvariable sollte im System korrekt erwähnt oder in Ihrem Befehlszeilenargument angegeben werden.
quelle
Da Ihr Code enthält
if __name__ == "__main__"
, der nicht als Paket importiert wird, sollten Siesys.path.append()
das Problem besser lösen.quelle
if __name__ == "__main__"
Ihre Datei einen Unterschied zu irgendetwas im Zusammenhang mit dem Importieren macht.