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.

War es hilfreich?

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:

  1. Das Verzeichnis der Eingabeskript (oder der Strom enthält, Verzeichnis).
  2. PYTHONPATH (eine Liste von Verzeichnisnamen, mit dem gleichen Syntax wie die Shell-Variable PATH).
  3. 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

gesucht
from . 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 ist   Users/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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top