Skript aus einem übergeordneten Verzeichnis importieren

77

Wie importiere ich ein Modul (Python-Datei), das sich im übergeordneten Verzeichnis befindet?

Beide Verzeichnisse enthalten eine __init__.pyDatei, aber ich kann immer noch keine Datei aus dem übergeordneten Verzeichnis importieren.

In diesem Ordnerlayout versucht Skript B, Skript A zu importieren:

Folder A:
   __init__.py
   Script A:
   Folder B:
     __init__.py
     Script B(attempting to import Script A)

Der folgende Code in Skript B funktioniert nicht:

import ../scriptA.py # I get a compile error saying the "." is invalid
sazr
quelle
Sie beantworten Ihre Frage nicht genau, aber wenn Sie init .py in Ordner A ausführen und versuchen, Ordner B oder Skript B zu importieren, wird Skript A erfolgreich in Skript B importiert.
Michael0x2a

Antworten:

76

Sie importieren keine Skripte in Python, Sie importieren Module. Einige Python-Module sind auch Skripte, die Sie direkt ausführen können (sie erledigen einige nützliche Arbeiten auf Modulebene).

Im Allgemeinen ist es vorzuziehen, absolute Importe anstelle von relativen Importen zu verwenden.

toplevel_package/
├── __init__.py
├── moduleA.py
└── subpackage
    ├── __init__.py
    └── moduleB.py

In moduleB:

from toplevel_package import moduleA

Wenn Sie moduleB.pyals Skript ausgeführt werden möchten, stellen Sie sicher, dass sich das übergeordnete Verzeichnis für toplevel_packagein Ihrem befindet sys.path.

jfs
quelle
8
Und warum sollten in diesem Fall keine sys path "Hacks" verwendet werden? Python macht es so schwer, hier ohne sie zu tun, was Sie wollen. Was genau ist der Nachteil hier?
BT
4
@BT « sys.path.append(path_to_parent)» sollte keine Antwort auf das Problem sein « « import ../scriptA.py # Ich erhalte einen Kompilierungsfehler, der besagt, dass die Frage "." Ungültig ist "» . Es gibt Fälle, in denen Änderungen sys.pathnützlich sein könnten, z. B. wenn Python selbst dies getan hat oder ein 3-Parteien-Modul, das alle import autopath; autopath.add_toplevel_to_syspath()Eckfälle korrekt behandelt, z. B. wenn automatisch das übergeordnete Verzeichnis von toplevel_package hinzugefügt wird sys.path, um eine direkte interne Modulausführung als zu ermöglichen Skript (oder in einer REPL) aus einem beliebigen Verzeichnis ohne ordnungsgemäße PYTHONPATH- oder (virtualenv) -Installation.
JFS
3
@JFSebastian Gibt es eine Art Vorschlag für eine Funktion, mit der wir explizit angeben können, was der Hauptordner oder das Hauptpaket des gesamten Projekts ist, damit wir uns nicht darum kümmern müssen, übergeordnete Verzeichnisse hinzuzufügen, sys.pathdamit wir Submodule auch als ausführen können Hauptdateien oder Skripte? Ich habe ein Projekt, in dem ich Skripte wirklich sowohl als Haupt- als auch als Modul ausführen muss, das importiert wird, aber ich muss Tonnen von Hacks ausführen, um Pfade hinzuzufügen sys.path, damit sie in beiden Fällen funktionieren. Würde die Arbeit in einer virtuellen Umgebung oder die Verwendung von Setuptools irgendwie funktionieren? Ich kämpfe wirklich damit ...
nbro
2
@nbro die Funktion heißt pip install main-package. Sie können bereits "Submodule" ausführen (verwenden Sie einfach deren absolute Namen, z python -ma.b.c. B. ). Wenn es unklar ist; fragen
jfs
8
Diese Lösung funktioniert bei mir nicht. Es wird ausgelöst: "ImportError: Kein Modul mit dem Namen toplevel_package"
smart
34

Aus den Dokumenten :

from .. import scriptA

Sie können dies in Paketen tun, jedoch nicht in Skripten, die Sie direkt ausführen. Über den obigen Link:

Beachten Sie, dass sowohl explizite als auch implizite relative Importe auf dem Namen des aktuellen Moduls basieren. Da der Name des Hauptmoduls immer "__main__" lautet, sollten Module, die als Hauptmodul einer Python-Anwendung verwendet werden sollen, immer absolute Importe verwenden.

Wenn Sie ein Skript erstellen, das ABB importiert, erhalten Sie den ValueError nicht.

Rob Wouters
quelle
28
ValueError: Versucht, relativen Import in Nicht-Paket
jgritty
3
@jgritty, das liegt daran, dass Sie es in einem Skript tun, das Sie direkt ausführen.
Rob Wouters
2
Ja, du hast Recht. Es wird funktionieren, wenn Sie ein Skript aufrufen, das dann Skript B importiert.
jgritty
6
@jgritty sys.path.append("..")ist, was Sie suchen
5
Endlich, 6 Jahre später, das Code-Snippet, nach dem ich gesucht habe!
jgritty
5

Wenn Sie das Skript direkt ausführen möchten, können Sie:

  1. Fügen Sie den Pfad des FolderA zur Umgebungsvariablen ( PYTHONPATH) hinzu.
  2. Fügen Sie den Pfad sys.pathin Ihrem Skript hinzu.

Dann:

import module_you_wanted
capfredf
quelle