Importieren eines Moduls aus einem relativen Pfad
-
07-07-2019 - |
Frage
Wie Importiere ich ein Python-Modul ist aufgrund seiner relativen Pfad?
Zum Beispiel, wenn dirFoo
enthält Foo.py
und dirBar
, und dirBar
enthält Bar.py
, wie Importiere ich Bar.py
in Foo.py
?
Hier ist eine visuelle Darstellung:
dirFoo\
Foo.py
dirBar\
Bar.py
Foo
aufnehmen will Bar
, aber die Umstrukturierung der Ordner-Hierarchie ist nicht eine option.
Lösung
Unter der Annahme, dass sowohl Ihre Verzeichnisse echte Python-Pakete sind (tun die __init__.py
Datei in sich haben), ist hier eine sichere Lösung für die Aufnahme von Modulen relativ zu der Position des Skripts.
Ich gehe davon aus, dass Sie dies tun wollen, weil Sie eine Reihe von Modulen mit Ihrem Skript müssen. Ich benutze diese in der Produktion in mehreren Produkten und arbeite in vielen speziellen Szenarien wie: Skripte aus einem anderen Verzeichnis oder ausgeführt mit Python genannt ausführen, anstatt eine neue Interpretin Öffnen
. import os, sys, inspect
# realpath() will make your script run, even if you symlink it :)
cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
if cmd_folder not in sys.path:
sys.path.insert(0, cmd_folder)
# Use this if you want to include modules from a subfolder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"subfolder")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
# Info:
# cmd_folder = os.path.dirname(os.path.abspath(__file__)) # DO NOT USE __file__ !!!
# __file__ fails if the script is called in different ways on Windows.
# __file__ fails if someone does os.chdir() before.
# sys.argv[0] also fails, because it doesn't not always contains the path.
Als Bonus, ist dieser Ansatz nicht lassen Sie Python zwingen Ihr Modul zu verwenden, anstatt der auf dem System installiert diejenigen.
Achtung! Ich weiß nicht wirklich, was geschieht, wenn der Strom-Modul innerhalb einer egg
Datei. Es wahrscheinlich nicht zu.
Andere Tipps
Werden Sie sicher, dass dirBar hat die __init__.py
Datei -- und das macht einem Verzeichnis in ein Python-Paket.
Sie können auch das Unterverzeichnis auf Ihren Python-Pfad hinzufügen, so dass es wie ein normales Skript importiert.
import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)
import mymodule
Just do einfache Dinge, die Py-Datei von einem anderen Ordner zu importieren.
Angenommen, Sie haben ein Verzeichnis wie:
lib/abc.py
Dann halten nur eine leere Datei in lib Ordner wie dem Namen
__init__.py
Und dann verwenden
from lib.abc import <Your Module name>
Halten Sie die __init__.py
Datei in jedem Ordner in der Hierarchie des Importmoduls.
Wenn Sie Ihr Projekt auf diese Weise strukturieren:
src\
__init__.py
main.py
dirFoo\
__init__.py
Foo.py
dirBar\
__init__.py
Bar.py
Dann von Foo.py sollten Sie in der Lage zu tun:
import dirFoo.Foo
Oder:
from dirFoo.Foo import FooObject
Per Tom Kommentar, dies erfordert, dass die src
Ordner entweder über site_packages
oder Suchpfad zugänglich ist. Auch, wie er erwähnt, wird __init__.py
implizit importiert, wenn Sie zuerst ein Modul in diesem Paket / Verzeichnis importieren. Typischerweise __init__.py
ist einfach eine leere Datei.
Die einfachste Methode ist sys.path.append () zu verwenden.
Sie können jedoch auch in der imp Modul. Es bietet Zugriff auf interne Importfunktionen.
# mod_name is the filename without the .py/.pyc extention
py_mod = imp.load_source(mod_name,filename_path) # Loads .py file
py_mod = imp.load_compiled(mod_name,filename_path) # Loads .pyc file
Dies kann dazu verwendet werden, um Module dynamisch zu laden, wenn Sie nicht über einen Modul der Namen kennen.
Ich habe dies in der Vergangenheit verwendet, um eine Plugin-Typ-Schnittstelle an eine Anwendung zu erstellen, in dem der Benutzer ein Skript mit anwendungsspezifischen Funktionen schreiben würde, und thier Skript nur in einem bestimmten Verzeichnis löschen.
Auch können diese Funktionen nützlich sein:
imp.find_module(name[, path])
imp.load_module(name, file, pathname, description)
Dies ist relevant PEP:
http://www.python.org/dev/peps/pep-0328 /
Insbesondere dirFoo Annahme ist ein Verzeichnis nach oben aus dirBar ...
In dirFoo \ Foo.py:
from ..dirBar import Bar
Der einfachste Weg, ohne Änderungen an Ihrem Skript ist PYTHONPATH-Umgebungsvariable zu setzen. Da sys.path wird von diesen Orten initialisiert:
- Das Verzeichnis der Eingabeskript (oder der Strom enthält, Verzeichnis).
- PYTHONPATH (eine Liste von Verzeichnisnamen, mit dem gleichen Syntax wie die Shell-Variable PATH).
- Die Installation abhängige Standard.
Führen Sie einfach:
export PYTHONPATH=/absolute/path/to/your/module
Sie sys.path Wille oben Pfad enthält, wie unten gezeigt:
print sys.path
['', '/absolute/path/to/your/module', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client', '/usr/lib/python2.7/dist-packages/ubuntuone-client', '/usr/lib/python2.7/dist-packages/ubuntuone-control-panel', '/usr/lib/python2.7/dist-packages/ubuntuone-couch', '/usr/lib/python2.7/dist-packages/ubuntuone-installer', '/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol']
Meiner Meinung nach die beste Wahl ist setzen __ init __. Py in den Ordner und rufen Sie die Datei mit
from dirBar.Bar import *
Es ist nicht zu verwenden sys.path.append empfohlen (), weil etwas schief gegangen wäre, wenn Sie den gleichen Dateinamen wie die vorhandene Python-Paket verwenden. Ich habe das nicht testen, aber das wird nicht eindeutig.
Die schnelle und unsaubere Art und Weise für Linux-Anwender
Wenn Sie gerade tüftelte und kümmern sich nicht um Bereitstellungsprobleme, können Sie einen symbolischen Link verwenden (vorausgesetzt, Ihr Dateisystem unterstützt) das Modul oder Paket direkt sichtbar in den Ordner des anfordernden Modul zu machen.
ln -s (path)/module_name.py
oder
ln -s (path)/package_name
Hinweis: Ein „Modul“ ist eine Datei mit einer Py-Erweiterung und ein „Paket“ ist jeder Ordner, der die Datei __init__.py
enthält (das eine leere Datei sein kann). Von einer Nutzungs Sicht Module und Pakete sind identisch -. Sowohl ihre enthaltenen „Definitionen und Erklärungen“ freizulegen, wie über den import
Befehl angefordert
Siehe auch: http://docs.python.org/2/tutorial/modules.html
from .dirBar import Bar
statt:
from dirBar import Bar
für den Fall, es könnte ein weiterer dirBar installiert sein und eine foo.py Leser verwirren.
Für diesen Fall Bar.py in Foo.py zu importieren, zuerst würde ich diese Ordner in Python-Pakete drehen wie folgt:
dirFoo\
__init__.py
Foo.py
dirBar\
__init__.py
Bar.py
Dann es so würde ich in Foo.py tun:
from .dirBar import Bar
Wenn ich die Namespacing aussehen Bar. was oder
gesuchtfrom . import dirBar
Wenn ich die Namespacing dirBar.Bar. wollte was . Dieser zweite Fall ist nützlich, wenn Sie mehr Module unter dem dirBar Paket haben.
Fügen Sie ein __ init __ py Datei:.
dirFoo\
Foo.py
dirBar\
__init__.py
Bar.py
Dann diesen Code hinzufügen zu Beginn der Foo.py:
import sys
sys.path.append('dirBar')
import Bar
Relative sys.path Beispiel:
# /lib/my_module.py
# /src/test.py
if __name__ == '__main__' and __package__ is None:
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../lib')))
import my_module
Basierend auf diese Antwort.
Nun, wie Sie erwähnen, in der Regel möchten Sie Zugriff auf einen Ordner mit Ihren Modulen relativ müssen, wo Ihr Haupt Skript ausgeführt wird, so dass Sie sie nur importieren.
Lösung:
Ich habe das Skript in D:/Books/MyBooks.py
und einigen Modulen (wie oldies.py). Ich muss von Unterverzeichnis D:/Books/includes
importieren:
import sys,site
site.addsitedir(sys.path[0] + '\\includes')
print (sys.path) # Just verify it is there
import oldies
Legen Sie eine print('done')
in oldies.py
, so überprüfen Sie alles in Ordnung geht. Auf diese Weise funktioniert immer, weil durch die sys.path
Python Definition wie beim Programmstart initialisiert, das erste Element dieser Liste path[0]
, ist das Verzeichnis, das das Skript enthält, das verwendet wurde, die Python-Interpreter aufgerufen werden kann.
Wenn das Skript Verzeichnis nicht verfügbar ist (zum Beispiel, wenn die Interpreter interaktiv aufgerufen wird, oder wenn das Skript von der Standardeingabe gelesen wird), path[0]
ist die leere Zeichenkette, die Python-Adresse verweist erste Module im aktuellen Verzeichnis zu suchen. Beachten Sie, dass das Skript Verzeichnis eingefügt wird, bevor die Einträge als Folge der PYTHONPATH
eingefügt.
Eine andere Lösung wäre, die py-erfordern Paket zu installieren und verwenden Sie dann den folgenden in Foo.py
import require
Bar = require('./dirBar/Bar')
Einfach können Sie: from Desktop.filename import something
Beispiel:
gegeben, dass der Dateiname
test.py
im Verzeichnis istUsers/user/Desktop
und wird Everthing importieren.
Sie den Code ein:
from Desktop.test import *
Aber stellen Sie sicher, dass Sie eine leere Datei „__init__.py
“ in diesem Verzeichnis mit dem Namen machen
Sehen Sie sich das pkgutil Modul aus der Standardbibliothek. Es kann helfen, Sie tun, was Sie wollen.
Hier ist eine Möglichkeit, eine Datei von einer Ebene zu importieren oben, den relativen Pfad verwendet wird.
Im Grunde nur bewegen Sie das Arbeitsverzeichnis auf eine Ebene (oder jede relative Position), hinzufügen, dass auf Ihren Weg, dann das Arbeitsverzeichnis bewegen zurück, wo es angefangen hat.
#to import from one level above:
cwd = os.getcwd()
os.chdir("..")
below_path = os.getcwd()
sys.path.append(below_path)
os.chdir(cwd)
Ich bin nicht über Python erfahren, so dass, wenn es eine falsch in meinen Worten, sagen Sie mir einfach. Wenn Ihre Dateihierarchie wie folgt angeordnet:
project\
module_1.py
module_2.py
module_1.py
definiert eine Funktion namens func_1()
, module_2.py :
from module_1 import func_1
def func_2():
func_1()
if __name__ == '__main__':
func_2()
und Sie laufen python module_2.py
in cmd, werden Sie es laufen, was func_1()
definiert. Das ist in der Regel, wie wir gleiche Hierarchie-Dateien importieren. Aber wenn man from .module_1 import func_1
in module_2.py
schreiben, wird Python-Interpreter No module named '__main__.module_1'; '__main__' is not a package
sagen. Also, dies zu beheben, halten wir nur die Veränderung, die wir gerade machen, und beide des Moduls zu einem Paket verschieben, und ein drittes Modul als Anrufer machen zu module_2.py
laufen.
project\
package_1\
module_1.py
module_2.py
main.py
main.py :
from package_1.module_2 import func_2
def func_3():
func_2()
if __name__ == '__main__':
func_3()
Aber der Grund, warum wir eine .
vor module_1
in module_2.py
hinzuzufügen ist, dass, wenn wir das nicht tun, und führen main.py
, Python-Interpreter No module named 'module_1'
sagen, das ist ein wenig schwierig, module_1.py
befindet sich direkt neben module_2.py
. Nun lasse ich func_1()
in module_1.py
etwas tun:
def func_1():
print(__name__)
, dass __name__
Aufzeichnungen, die func_1 nennt. Jetzt halten wir die .
vor module_1
, laufen main.py
, wird es package_1.module_1
drucken, nicht module_1
. Es zeigt an, dass derjenige, der func_1()
ruft in der gleichen Hierarchie wie main.py
ist, bedeutet das, dass .
module_1
auf derselben Hierarchie wie module_2.py
selbst ist. Also, wenn es nicht ein Punkt ist, main.py
module_1
auf derselben Hierarchie wie sie zu erkennen, kann es package_1
, erkennt aber nicht, was „unter“ es.
Nun wollen wir es ein bisschen machen kompliziert. Sie haben einen config.ini
und ein Modul definiert eine Funktion, die sie in der gleichen Hierarchie wie ‚main.py‘ zu lesen.
project\
package_1\
module_1.py
module_2.py
config.py
config.ini
main.py
Und aus irgendeinem Grunde unvermeidbar, haben Sie es mit module_2.py
zu nennen, so hat es von den oberen Hierarchie importieren module_2.py .
import ..config
pass
Zwei Punkte: die Einfuhr von den oberen Hierarchie (drei Punkte oberen Zugang als oberes und so weiter). Jetzt laufen wir main.py
, wird der Dolmetscher sagen: ValueError:attempted relative import beyond top-level package
. Das „Top-Level-Paket“ an hier ist main.py
. Nur weil config.py
neben main.py
ist, sie in derselben Hierarchie ist, ist config.py
nicht „unter“ main.py
, oder es ist nicht „verbleit“ von main.py
, so ist es darüber hinaus main.py
. Um dies zu beheben, ist der einfachste Weg ist:
project\
package_1\
module_1.py
module_2.py
config.py
config.ini
main.py
ich denke, das ist mit dem Grundsatz übereinstimmen Projektdateihierarchie anordnen, sollten Sie Module mit unterschiedlicher Funktion in verschiedenen Ordnern organisieren, und nur einen Top-Anrufer in außen verlassen, und Sie können importieren, wie immer Sie wollen.
Dies funktioniert auch, und ist viel einfacher, als alles, was mit dem sys
Modul:
with open("C:/yourpath/foobar.py") as f:
eval(f.read())
Rufen Sie mich an übervorsichtig, aber Ich mag meine mehr tragbar machen, weil es nicht sicher ist, anzunehmen, dass die Dateien immer an der gleichen Stelle auf jedem Computer sein werden. Persönlich habe ich den Code sieht zuerst den Dateipfad. Ich benutze Linux so meins würde wie folgt aussehen:
import os, sys
from subprocess import Popen, PIPE
try:
path = Popen("find / -name 'file' -type f", shell=True, stdout=PIPE).stdout.read().splitlines()[0]
if not sys.path.__contains__(path):
sys.path.append(path)
except IndexError:
raise RuntimeError("You must have FILE to run this program!")
Das ist natürlich, wenn Sie planen, diese zusammen zu verpacken. Aber wenn das der Fall ist Sie nicht wirklich braucht zwei separate Dateien trotzdem.