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 aus mod2
importieren. Wie soll ich das machen
Ich habe from ..sub2 import mod2
ausprobiert, erhalte aber die Meldung "Versuchter relativer Import in Nicht-Paket".
Ich habe herumgegoogelt, aber nur "sys.path
manipulation" -Hacks gefunden. Gibt es nicht einen sauberen Weg?
Bearbeiten: Alle meine __init__.py
sind derzeit leer
Edit2: Ich versuche dies zu tun, weil 2 Klassen enthält, die über Unterpakete (sub1
, subX
, etc.) geteilt werden.
Edit3: Das Verhalten, nach dem ich suche, ist dasselbe wie in PEP 366 (danke John B) beschrieben.
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 die Datei mod1.py als Argument an den Interpreter übergeben.
Von PEP 328 :
Relative Importe verwenden das Attribut __ eines Moduls, um die Position dieses Moduls in der Pakethierarchie zu bestimmen. Wenn der Name des Moduls keine Paketinformationen enthält (z. B. '__main__'), 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.
In Python 2.6 können sie Module relativ zum Hauptmodul 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.
main.py
setup.py
app/ ->
__init__.py
package_a/ ->
__init__.py
module_a.py
package_b/ ->
__init__.py
module_b.py
python main.py
aus.main.py
macht: import app.package_a.module_a
module_a.py
macht import app.package_b.module_b
Alternativ könnten 2 oder 3 verwenden: from app.package_a import module_a
Das funktioniert, solange Sie app
in Ihrem PYTHONPATH haben. main.py
könnte dann überall sein.
Sie schreiben also einen setup.py
, um das gesamte App-Paket und die Unterpakete in die python -Ordner des Zielsystems und main.py
in die Skriptordner des Zielsystems zu kopieren (zu installieren).
Hier ist die Lösung, die für mich funktioniert:
Ich führe die relativen Importe als from ..sub2 import mod2
aus. Wenn ich dann mod1.py
ausführen möchte, gehe ich zum übergeordneten Verzeichnis von app
und führe das Modul mit dem python aus. -m wechsle als python -m app.sub1.mod1
.
Der eigentliche Grund, warum dieses Problem bei relativen Importen auftritt, ist, dass relative Importe funktionieren, indem die __name__
-Eigenschaft des Moduls verwendet wird. Wenn das Modul direkt ausgeführt wird, wird __name__
auf __main__
gesetzt und enthält keine Informationen zur Paketstruktur. Und deshalb beschwert sich python über den relative import in non-package
-Fehler.
Wenn Sie also den Schalter -m verwenden, geben Sie die Paketstrukturinformationen an Python weiter, wodurch 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 in allen Dateien Code für die Auflistung von Stichwörtern eingefügt werden muss. (Obwohl einige der Kommentare dank @ncoghlan und @XiongChiamiov wirklich hilfreich waren)
Hoffe, das hilft jemandem, der mit relativen Importproblemen kämpft, denn das Durchlaufen von PEP macht wirklich keinen Spaß.
"Guido betrachtet das Ausführen von Skripten in einem Paket als Anti-Pattern" (abgelehnt PEP-3122 )
Ich habe so viel Zeit damit verbracht, nach einer Lösung zu suchen, verwandte Posts hier auf Stack Overflow zu lesen und mir zu sagen: "Es muss einen besseren Weg geben!". Sieht so aus, als gäbe es das nicht.
Dies ist zu 100% gelöst:
Importiere settings/local_setting.py in app/main.py:
main.py:
import sys
sys.path.insert(0, "../settings")
try:
from local_settings import *
except ImportError:
print('No Import')
def import_path(fullpath):
"""
Import a file with full path specification. Allows one to
import from anywhere, something __import__ does not do.
"""
path, filename = os.path.split(fullpath)
filename, ext = os.path.splitext(filename)
sys.path.append(path)
module = __import__(filename)
reload(module) # Might be out of date
del sys.path[-1]
return module
Ich benutze dieses Snippet, um Module von Pfaden zu importieren, hoffe das hilft
erklärung von nosklo's
mit Beispielen beantworten
Hinweis: Alle __init__.py
-Dateien sind leer.
main.py
app/ ->
__init__.py
package_a/ ->
__init__.py
fun_a.py
package_b/ ->
__init__.py
fun_b.py
def print_a():
print 'This is a function in dir package_a'
from app.package_a.fun_a import print_a
def print_b():
print 'This is a function in dir package_b'
print 'going to call a function in dir package_a'
print '-'*30
print_a()
from app.package_b import fun_b
fun_b.print_b()
wenn Sie $ python main.py
ausführen, wird Folgendes zurückgegeben:
This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
from app.package_b import fun_b
from app.package_a.fun_a import print_a
also Datei im Ordner package_b
Verwendete Datei im Ordner package_a
, was Sie wollen. Richtig??
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.
was ich tun wollte, war das folgende (das Modul, von dem ich arbeitete, war Modul3):
mymodule\
__init__.py
mymodule1\
__init__.py
mymodule1_1
mymodule2\
__init__.py
mymodule2_1
import mymodule.mymodule1.mymodule1_1
Beachten Sie, dass ich mymodule bereits installiert habe, in meiner Installation jedoch nicht "mymodule1".
und ich würde einen ImportError bekommen, weil er versuchte, von meinen installierten Modulen zu importieren.
Ich habe versucht, ein sys.path.append zu machen, und das hat nicht funktioniert. Was funktioniert hat war ein sys.path.insert
if __== '__main__':
sys.path.insert(0, '../..')
So eine Art Hack, aber es hat alles geklappt! 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, sie sollten die Funktion "Anhängen" an sys.path verwenden, aber das funktioniert nicht, wenn Sie bereits ein Modul definiert haben (ich finde es sehr seltsames Verhalten).
Lassen Sie mich dies hier nur zu meiner eigenen 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.
import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
Wie @EvgeniSergeev in den Kommentaren zum OP sagt, können Sie Code aus einer .py
-Datei an einem beliebigen Ort importieren:
import imp
foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()
Dies wird aus dieser SO Antwort entnommen.
Schauen Sie sich http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports an. Du könntest es tun
from .mod1 import stuff
From Python doc ,
In Python 2.5 können Sie das Verhalten des Imports mithilfe einer
from __future__ import absolute_import
-Direktive in absolute Importe ändern. Dieses absolute Importverhalten wird in einer zukünftigen Version zum Standard (wahrscheinlich Python 2.7). Sobald der absolute Import die Standardeinstellung ist, findetimport string
immer die Version der Standardbibliothek. Es wird empfohlen, dass Benutzer anfangen, absolute Importe so weit wie möglich zu verwenden. Daher ist es vorzuziehen,from pkg import string
in Ihren Code zu schreiben
Zusätzlich zu dem, was John B gesagt hat, scheint es hilfreich zu sein, die Variable __package__
zu setzen, anstatt __main__
zu ändern, was andere Dinge vermasseln könnte. Aber soweit ich es testen konnte, funktioniert es nicht ganz so, wie es sollte.
Ich habe das gleiche Problem und weder PEP 328 noch PEP 366 lösen das Problem vollständig, da beide am Ende des Tages den Kopf des Pakets in sys.path
enthalten müssen, soweit ich das verstehen kann.
Ich sollte auch erwähnen, dass ich nicht gefunden habe, wie die Zeichenfolge formatiert werden soll, die in diese Variablen eingefügt werden soll. Ist es "package_head.subfolder.module_name"
oder was?
Ich fand es einfacher, die Umgebungsvariable "PYTHONPATH" auf den obersten Ordner zu setzen:
bash$ export PYTHONPATH=/PATH/TO/APP
dann:
import sub1.func1
#...more import
natürlich ist PYTHONPATH "global", aber es hat mir noch keine Probleme bereitet.