Stellen Sie sich diese Verzeichnisstruktur vor:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
Ich codiere mod1
und muss etwas importieren mod2
. Wie soll ich das machen
Ich habe es versucht, from ..sub2 import mod2
aber ich erhalte einen "Versuchten relativen Import in Nicht-Paket".
Ich googelte herum, fand aber nur " sys.path
Manipulations" -Hacks. Gibt es keinen sauberen Weg?
Bearbeiten: Alle meine __init__.py
sind derzeit leer
Edit2: Ich versuche , dies zu tun , weil sub2 Klassen enthält , die über Unter Pakete geteilt werden ( sub1
, subX
usw.).
Edit3: Das gesuchte Verhalten ist das gleiche wie in PEP 366 beschrieben (danke John B)
Antworten:
Jeder scheint Ihnen sagen zu wollen, was Sie tun sollten, anstatt nur die Frage zu beantworten.
Das Problem ist, dass Sie das Modul als '__main__' ausführen, indem Sie mod1.py als Argument an den Interpreter übergeben.
Aus PEP 328 :
In Python 2.6 wird die Möglichkeit hinzugefügt, Module relativ zum Hauptmodul zu referenzieren. PEP 366 beschreibt die Änderung.
Update : Laut Nick Coghlan besteht die empfohlene Alternative darin, das Modul innerhalb des Pakets mit dem Schalter -m auszuführen.
quelle
-m
Switch auszuführen , anstatt ihren Dateinamen direkt anzugeben.from sub2 import mod2
. Um mod1 in der App auszuführen, tun Sie diespython -m sub1.mod1
.Hier ist die Lösung, die für mich funktioniert:
Ich mache die relativen Importe als
from ..sub2 import mod2
und wenn ich dann ausführen möchte,mod1.py
gehe ich in das übergeordnete Verzeichnis vonapp
und führe das Modul mit dem Python-m-Schalter als auspython -m app.sub1.mod1
.Der wahre Grund, warum dieses Problem bei relativen Importen auftritt, besteht darin, dass relative Importe funktionieren, indem die
__name__
Eigenschaft des Moduls übernommen wird. Wenn das Modul direkt ausgeführt wird,__name__
ist es auf gesetzt__main__
und enthält keine Informationen zur Paketstruktur. Und deshalb beschwert sich Python über denrelative import in non-package
Fehler.Mit dem Schalter -m stellen Sie Python die Paketstrukturinformationen zur Verfügung, mit denen die relativen Importe erfolgreich aufgelöst werden können.
Ich habe dieses Problem oft beim relativen Importieren festgestellt. Und nachdem ich alle vorherigen Antworten gelesen hatte, war ich immer noch nicht in der Lage, herauszufinden, wie ich es auf saubere Weise lösen kann, ohne dass ich in alle Dateien Code auf dem Boilerplate einfügen muss. (Obwohl einige der Kommentare dank @ncoghlan und @XiongChiamiov wirklich hilfreich waren)
Ich hoffe, dies hilft jemandem, der mit relativen Importproblemen zu kämpfen hat, denn das Durchlaufen von PEP macht wirklich keinen Spaß.
quelle
-m
das gelöst werden sollte.from . import some_module
.python main.py
.main.py
tut:import app.package_a.module_a
module_a.py
tutimport app.package_b.module_b
Alternativ könnten 2 oder 3 verwenden:
from app.package_a import module_a
Das wird funktionieren, solange Sie
app
in Ihrem PYTHONPATH haben.main.py
könnte dann überall sein.Sie schreiben also ein
setup.py
, um das gesamte App-Paket und die Unterpakete in die Python-Ordner des Zielsystems und in die Skriptordner des Zielsystems zu kopieren (zu installieren)main.py
.quelle
"Guido betrachtet das Ausführen von Skripten innerhalb eines Pakets als Anti-Pattern" (abgelehntes PEP-3122 )
Ich habe so viel Zeit damit verbracht, nach einer Lösung zu suchen, verwandte Beiträge hier auf Stack Overflow zu lesen und mir zu sagen: "Es muss einen besseren Weg geben!". Sieht so aus, als gäbe es keine.
quelle
-m
switch: ausführenpython -m app.sub1.mod1
oderapp.sub1.mod1.main()
von einem Skript der obersten Ebene aus aufrufen (z. B. generiert aus den in setup.py definierten Eintrittspunkten von setuptools).Dies ist zu 100% gelöst:
Importieren Sie settings / local_setting.py in app / main.py:
main.py:
quelle
sys.path.insert(0, "../settings")
und dannfrom local_settings import *
Ich verwende dieses Snippet, um Module aus Pfaden zu importieren. Ich hoffe, das hilft
quelle
Erklärung der
nosklo's
Antwort mit BeispielenHinweis: Alle
__init__.py
Dateien sind leer.app / package_a / fun_a.py
app / package_b / fun_b.py
main.py.
Wenn Sie es ausführen
$ python main.py
, wird Folgendes zurückgegeben:from app.package_b import fun_b
from app.package_a.fun_a import print_a
Also Datei in Ordner
package_b
verwendet Datei in Ordnerpackage_a
, was Sie wollen. Recht??quelle
Dies ist leider ein sys.path-Hack, aber es funktioniert ganz gut.
Ich bin auf dieses Problem mit einer anderen Ebene gestoßen: Ich hatte bereits ein Modul mit dem angegebenen Namen, aber es war das falsche Modul.
Ich wollte Folgendes tun (das Modul, an dem ich arbeitete, war Modul 3):
Beachten Sie, dass ich mymodule bereits installiert habe, aber in meiner Installation nicht "mymodule1" habe.
und ich würde einen ImportError erhalten, weil versucht wurde, von meinen installierten Modulen zu importieren.
Ich habe versucht, einen sys.path.append zu erstellen, und das hat nicht funktioniert. Was funktionierte, war ein sys.path.insert
So eine Art Hack, aber alles hat funktioniert! Denken Sie also daran, wenn Sie möchten, dass Ihre Entscheidung andere Pfade überschreibt , müssen Sie sys.path.insert (0, Pfadname) verwenden, damit es funktioniert! Dies war ein sehr frustrierender Knackpunkt für mich. Viele Leute sagen, dass sie die Funktion "Anhängen" an sys.path verwenden sollen, aber das funktioniert nicht, wenn Sie bereits ein Modul definiert haben (ich finde es sehr seltsam).
quelle
sys.path.append('../')
funktioniert gut für mich (Python 3.5.2)Lassen Sie mich dies hier nur als meine eigene Referenz setzen. Ich weiß, dass es kein guter Python-Code ist, aber ich brauchte ein Skript für ein Projekt, an dem ich arbeitete, und ich wollte das Skript in ein
scripts
Verzeichnis stellen.quelle
Wie @EvgeniSergeev in den Kommentaren zum OP sagt, können Sie Code aus einer
.py
Datei an einem beliebigen Ort importieren mit:Dies ist aus dieser SO-Antwort entnommen .
quelle
Schauen Sie sich http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports an . Du könntest es tun
quelle
Aus Python doc ,
quelle
Ich fand es einfacher, die Umgebungsvariable "PYTHONPATH" auf den obersten Ordner zu setzen:
dann:
Natürlich ist PYTHONPATH "global", aber es hat mir noch keine Probleme bereitet.
quelle
virtualenv
können Sie im Wesentlichen Ihre Importanweisungen verwalten.Zusätzlich zu dem, was John B gesagt hat, scheint es, als ob das Setzen der
__package__
Variablen helfen sollte, anstatt zu ändern,__main__
was andere Dinge vermasseln könnte. Aber soweit ich testen konnte, funktioniert es nicht ganz so, wie es sollte.Ich habe das gleiche Problem und weder PEP 328 noch 366 lösen das Problem vollständig, da beide am Ende des Tages den Kopf des Pakets benötigen
sys.path
, soweit ich verstehen kann.Ich sollte auch erwähnen, dass ich nicht gefunden habe, wie die Zeichenfolge formatiert werden soll, die in diese Variablen eingehen soll. Ist es
"package_head.subfolder.module_name"
oder was?quelle
Sie müssen den Pfad des Moduls an Folgendes anhängen
PYTHONPATH
:quelle
sys.path
, dasys.path
aus initialisiert wirdPYTHONPATH
sys.path
muss aber im Quellcode fest codiert werden, im Gegensatz dazuPYTHONPATH
ist dies eine Umgebungsvariable und kann exportiert werden.