Ich verwende Python 2.5.
Dies ist mein Ordnerbaum:
ptdraft/
nib.py
simulations/
life/
life.py
(Ich habe auch __init__.py
in jedem Ordner, hier zur besseren Lesbarkeit weggelassen)
Wie importiere ich das nib
Modul aus dem life
Modul heraus? Ich hoffe, dass es möglich ist, auf sys.path zu basteln.
Hinweis: Das Hauptmodul, das ausgeführt wird, befindet sich im ptdraft
Ordner.
__init__.py
. S.Lott: Ich weiß nicht, wie ich das überprüfen soll ...sys.path
oderPYTHONPATH
Antworten zu überspringen und die ausgezeichnete Antwort von np8 zu lesen . Ja, es ist eine lange Lektüre. Ja, es sieht nach viel Arbeit aus. Aber es ist die einzige Antwort, die das Problem tatsächlich richtig und sauber löst.Antworten:
Es scheint, dass das Problem nicht damit zusammenhängt, dass sich das Modul in einem übergeordneten Verzeichnis befindet oder so etwas.
Sie müssen das Verzeichnis, das
ptdraft
PYTHONPATH enthält , hinzufügenSie sagten, das
import nib
hat bei Ihnen funktioniert, das bedeutet wahrscheinlich, dass Sie sichptdraft
selbst (nicht das übergeordnete Element) zu PYTHONPATH hinzugefügt haben.quelle
import sys
und dannsys.path.append("..\<parent_folder>")
Sie können relative Importe verwenden (Python> = 2.5):
(Was ist neu in Python 2.5?) PEP 328: Absolute und relative Importe
BEARBEITEN : Ein weiterer Punkt '.' zwei Pakete hochgehen
quelle
ValueError: Attempted relative import in non-package
__init__.py
Datei.__init__.py
nicht das einzige ist, was Sie tun müssen: stackoverflow.com/questions/11536764/…Relative Importe (wie in
from .. import mymodule
) funktionieren nur in einem Paket. So importieren Sie 'mymodule', das sich im übergeordneten Verzeichnis Ihres aktuellen Moduls befindet:Bearbeiten : Das
__file__
Attribut wird nicht immer angegeben. Anstatt zu verwenden,os.path.abspath(__file__)
schlug ich jetzt vor, das Inspect-Modul zu verwenden, um den Dateinamen (und den Pfad) der aktuellen Datei abzurufenquelle
sys.path.insert(1, os.path.join(sys.path[0], '..'))
parentdir
, aber in einem der bereits angegebenen Pfadesys.path
gibt es ein anderes Modul mit dem Namen 'mymodule'. Durch Einfügen vonparentdir
als erstes Element dersys.path
Liste wird sichergestellt, dassparentdir
stattdessen das Modul von importiert wird.sys.path.insert(1, os.path.realpath(os.path.pardir))
funktioniert auch.Eine ähnliche Antwort habe ich auch auf die Frage nach Importen aus Geschwisterpaketen gepostet. Sie können es hier sehen .
Lösung ohne
sys.path
HacksZusammenfassung
packaged_stuff
)setup.py
in dem Sie setuptools.setup () verwenden .pip install -e <myproject_folder>
from packaged_stuff.modulename import function_name
Installieren
Ich gehe von der gleichen Ordnerstruktur aus wie in der Frage
Ich rufe den
.
Stammordner auf und in meinem Fall befindet er sich inC:\tmp\test_imports
.Schritte
1) Fügen Sie a
setup.py
zum Stammordner hinzuDer Inhalt der
setup.py
kann einfach seinGrundsätzlich würde "any"
setup.py
funktionieren. Dies ist nur ein minimales Arbeitsbeispiel.2) Verwenden Sie eine virtuelle Umgebung
Wenn Sie mit virtuellen Umgebungen vertraut sind, aktivieren Sie eine und fahren Sie mit dem nächsten Schritt fort. Die Verwendung von virtuellen Umgebungen sind nicht unbedingt erforderlich, aber sie werden wirklich Sie auf lange Sicht helfen (wenn Sie mehr als 1 Projekt laufenden haben ..). Die grundlegendsten Schritte sind (im Stammordner ausführen)
python -m venv venv
. /venv/bin/activate
(Linux) oder./venv/Scripts/activate
(Win)Um mehr darüber zu erfahren, googeln Sie einfach "python virtualenv tutorial" oder ähnliches. Sie benötigen wahrscheinlich nie andere Befehle als das Erstellen, Aktivieren und Deaktivieren.
Sobald Sie eine virtuelle Umgebung erstellt und aktiviert haben, sollte Ihre Konsole den Namen der virtuellen Umgebung in Klammern angeben
3) Pip Installieren Sie Ihr Projekt im bearbeitbaren Zustand
Installieren Sie Ihr Top-Level-Paket
myproject
mitpip
. Der Trick besteht darin,-e
bei der Installation das Flag zu verwenden . Auf diese Weise wird es in einem bearbeitbaren Zustand installiert, und alle an den .py-Dateien vorgenommenen Änderungen werden automatisch in das installierte Paket aufgenommen.Führen Sie im Stammverzeichnis aus
pip install -e .
(Beachten Sie den Punkt, er steht für "aktuelles Verzeichnis")Sie können auch sehen, dass es mithilfe von installiert wird
pip freeze
4) Importieren Sie
mainfolder
vor jedem ImportIn diesem Beispiel
mainfolder
wäre dasptdraft
. Dies hat den Vorteil, dass Sie nicht auf Namenskollisionen mit anderen Modulnamen (aus der Python-Standardbibliothek oder Modulen von Drittanbietern) stoßen.Beispiel Verwendung
nib.py.
life.py
Laufen life.py
quelle
sys.path
und in denen der Code normalerweise von Endbenutzern installiert wird. Das ist besser alssys.path
Hacks (und Sie können PYTHONPATH in diese Kategorie von Pfad-Hacks aufnehmen), da sich der in der Entwicklung befindliche Code für Sie genauso verhalten sollte wie für andere Benutzer. Im Gegensatz dazu werden Importanweisungen bei Verwendung von Pfadänderungen auf andere Weise aufgelöst.Sie können den betriebssystemabhängigen Pfad im "Modul-Suchpfad" verwenden, der in sys.path aufgeführt ist . So können Sie einfach übergeordnetes Verzeichnis wie folgt hinzufügen
Wenn Sie ein Eltern-Eltern-Verzeichnis hinzufügen möchten,
Dies funktioniert sowohl in Python 2 als auch in Python 3.
quelle
Wenn das Hinzufügen Ihres Modulordners zum PYTHONPATH nicht funktioniert hat, können Sie die Liste sys.path in Ihrem Programm ändern, in der der Python-Interpreter nach den zu importierenden Modulen sucht. In der Python-Dokumentation heißt es:
Wenn Sie dies wissen, können Sie in Ihrem Programm Folgendes tun:
quelle
/path/to/ptdraft
müsste es bearbeitet werden. Es gibt Lösungen, die das aktuelle Verzeichnis der Datei ermitteln und auf diese Weise auch aus dem übergeordneten Ordner importieren.Sie wissen nicht viel über Python 2.
In Python 3 kann der übergeordnete Ordner wie folgt hinzugefügt werden:
... und dann kann man Module daraus importieren
quelle
'..'
zu dem Verzeichnis mit dem betreffenden Modul führt.Hier ist eine einfache Antwort, damit Sie sehen können, wie es funktioniert, klein und plattformübergreifend.
Es werden nur integrierte Module (
os
,sys
undinspect
) verwendet, daher sollte esauf jedem Betriebssystem funktionieren, da Python dafür entwickelt wurde.
Kürzerer Code für die Antwort - weniger Zeilen und Variablen
Ersetzen Sie für weniger Zeilen die zweite Zeile durch
import os.path as path, sys, inspect
,fügen Sie
inspect.
am Anfang vongetsourcefile
(Zeile 3) hinzu und entfernen Sie die erste Zeile.- Dies importiert jedoch das gesamte Modul und benötigt möglicherweise mehr Zeit, Speicher und Ressourcen.
Der Code für meine Antwort ( längere Version )
Es wird ein Beispiel aus einer Stack Overflow-Antwort verwendet. Wie erhalte ich den Pfad der aktuell
ausgeführten Datei in Python? um die Quelle (Dateiname) des laufenden Codes mit einem integrierten Tool zu finden.
Mein Code fügt
sys.path
der Python- Pfadliste einen Dateipfad hinzu ,da Python so Module aus diesem Ordner importieren kann.
Nach dem Importieren eines Moduls in den Code empfiehlt es sich,
sys.path.pop(0)
in einer neuen Zeile zu arbeiten,wenn dieser hinzugefügte Ordner ein Modul mit demselben Namen wie ein anderes Modul enthält, das
später im Programm importiert wird . Sie müssen das vor dem Import hinzugefügte Listenelement entfernen, nicht andere Pfade.
Wenn Ihr Programm keine anderen Module importiert, können Sie den Dateipfad nicht löschen, da
nach dem Beenden eines Programms (oder dem Neustart der Python-Shell) alle Änderungen an vorgenommen werden
sys.path
verschwinden.Hinweise zu einer Dateinamenvariablen
In meiner Antwort wird die
__file__
Variable nicht verwendet , um den Dateipfad / Dateinamen des ausgeführtenCodes abzurufen, da Benutzer ihn hier häufig als unzuverlässig beschrieben haben . Sie sollten es nicht
zum Importieren von Modulen aus dem übergeordneten Ordner in Programmen verwenden, die von anderen Personen verwendet werden.
Einige Beispiele, bei denen es nicht funktioniert (Zitat aus dieser Frage zum Stapelüberlauf):
• Auf einigen Plattformen kann es nicht gefunden werden. • Manchmal ist es nicht der vollständige Dateipfad
quelle
sys.path.pop(0)
sofort nach dem Import des gewünschten Moduls entfernt. Nachfolgende Importe gingen jedoch immer noch an diesen Ort. Zum Beispiel habe ichapp/config
,app/tools
undapp/submodule/config
. Vonsubmodule
füge ichapp/
zum Importieren eintools
, entferne dannapp/
und versuche zu importierenconfig
, aber ich bekommeapp/config
stattdessenapp/submodule/config
.tools
Importe auchconfig
aus dem übergeordneten Verzeichnis importierte . Als ich später versuchte,sys.path.pop(0); import config
drinnen etwas zu tunsubmodule
, erwarteteapp/submodule/config
ich es tatsächlich zu bekommenapp/config
. Offensichtlich gibt Python eine zwischengespeicherte Version eines Moduls mit demselben Namen zurück, anstatt tatsächlichsys.path
nach einem Modul zu suchen, das diesem Namen entspricht.sys.path
In diesem Fall wurde es korrekt geändert. Python überprüfte es nur nicht, da das gleichnamige Modul bereits geladen wurde.sys.modules
... sys.modules nachgeschlagen. Durch Löschen eines Schlüssels wird der Cache-Eintrag für das genannte Modul ungültig, sodass Python beim nächsten Import erneut sucht. ... Beachten Sie jedoch, dass die beiden Objekte unterschiedlich sind, wenn Sie einen Verweis auf das Modulobjekt behalten, dessen Cache ungültig machen und dann erneut importieren. Im Gegensatz dazuimportlib.reload()
wird der Modulinhalt wiederverwendet und neu initialisiert ...os.path.realpath(getsourcefile(lambda:0) + "/../..")
. Wird die aktuelle Quelldatei mit zwei übergeordneten Verzeichnissymbolen angehängt. Ich habe nicht verwendet,os.path.sep
dagetsourcefile
eine Zeichenfolge/
auch unter Windows zurückgegeben wurde.realpath
sorgt dafür, dass zwei Verzeichniseinträge aus dem vollständigen Pfad (in diesem Fall dem Dateinamen und dann dem aktuellen Verzeichnis) entfernt werden, der das übergeordnete Verzeichnis angibt.Hier ist eine allgemeinere Lösung, die das übergeordnete Verzeichnis in sys.path enthält (funktioniert für mich):
quelle
import os, sys\n sys.path.insert(0,os.path.pardir)
das Gleiche, aber sorther :) (keine Zeilen in Kommentaren)os.path.pardir
Sie nicht den Realpfad des Elternteils, sondern nur den relativen Pfad, von dem aus Sie densys.path.insert()
__file__
Variable, die unzuverlässig sein kann (nicht immer der vollständige Dateipfad, funktioniert nicht auf jedem Betriebssystem usw.), wie StackOverflow-Benutzer häufig erwähnt haben. Wenn Sie die Antwort so ändern, dass sie nicht enthalten ist, treten weniger Probleme auf und sie ist besser kompatibel. Weitere Informationen finden Sie unter stackoverflow.com/a/33532002/3787376 .Ich fand die folgende Methode zum Importieren eines Pakets aus dem übergeordneten Verzeichnis des Skripts. Im Beispiel möchte ich Funktionen
env.py
aus demapp.db
Paket importieren .quelle
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
sys.path
zu modifizieren ist normalerweise eine schlechte Idee. Sie müssen einen Weg ( zB ,PYTHONPATH
) für Ihre Bibliothek zugänglich sein , anderen Code (oder es ist sonst nicht wirklich eine Bibliothek); benutze das einfach die ganze Zeit!Die oben genannten Lösungen sind ebenfalls in Ordnung. Eine andere Lösung für dieses Problem ist
Wenn Sie etwas aus dem Verzeichnis der obersten Ebene importieren möchten. Dann,
Wenn Sie ein Modul aus dem übergeordneten Verzeichnis importieren möchten. Dann,
Wenn Sie ein Modul aus dem übergeordneten Verzeichnis importieren möchten. Dann,
Auf diese Weise können Sie eine bestimmte Methode importieren, wenn Sie möchten.
quelle
sys.path.append
obigen Hacks und ich kann meine Bibliothek nicht so importieren. Dies ist, was ich zuerst versucht habe, bevor ich anfing zu googeln :) Ok, es war dasValueError: attempted relative import beyond top-level package
Für mich ist der kürzeste und mein Lieblings-Oneliner für den Zugriff auf das übergeordnete Verzeichnis:
oder:
os.getcwd () gibt den Namen des aktuellen Arbeitsverzeichnisses zurück, os.path.dirname (Verzeichnisname) gibt den Verzeichnisnamen für das übergebene zurück.
Meiner Meinung nach sollte die Python-Projektarchitektur so ausgeführt werden, dass kein Modul aus dem untergeordneten Verzeichnis ein Modul aus dem übergeordneten Verzeichnis verwendet. Wenn so etwas passiert, lohnt es sich, über den Projektbaum nachzudenken.
Eine andere Möglichkeit besteht darin, der Systemumgebungsvariablen PYTHONPATH ein übergeordnetes Verzeichnis hinzuzufügen.
quelle
In einem Jupyter-Notizbuch
Solange Sie in einem Jupyter-Notizbuch arbeiten, kann diese kurze Lösung hilfreich sein:
Es funktioniert auch ohne
__init__.py
Datei.Ich habe es mit Anaconda3 unter Linux und Windows 7 getestet.
quelle
%cd -
nach dem Import hinzuzufügen , damit das aktuelle Verzeichnis des Notebooks unverändert bleibt?import sys sys.path.append('../')
quelle
Wenn Sie sich nicht in einer
__init__.py
Paketumgebung mit Dateien befinden, ist es mit der pathlib-Bibliothek (in> = Python 3.4 enthalten) sehr übersichtlich und intuitiv, den Pfad des übergeordneten Verzeichnisses an PYTHONPATH anzuhängen:quelle
gleiche Art von Stil wie die vorherige Antwort - aber in weniger Zeilen: P.
Datei gibt den Speicherort zurück, an dem Sie arbeiten
quelle
Arbeiten Sie mit Bibliotheken. Erstellen Sie eine Bibliothek namens nib, installieren Sie sie mit setup.py, lassen Sie sie in Site-Paketen gespeichert und Ihre Probleme sind gelöst. Sie müssen nicht alles, was Sie machen, in ein einziges Paket packen. Zerbrich es in Stücke.
quelle
site-packages
jedes Mal einsetzen, wenn sie es auf einem anderen Computer ausführen.In einem Linux-System können Sie einen Softlink vom Ordner "life" zur Datei nib.py erstellen. Dann können Sie es einfach wie folgt importieren:
quelle