it-swarm.com.de

Relativer Import in Python 3 funktioniert nicht

Ich habe folgendes Verzeichnis:

mydirectory
├── __init__.py
├── file1.py 
└── file2.py

Ich habe eine Funktion f in file1.py definiert.

Wenn in file2.py, mache ich

from .file1 import f

Ich erhalte folgende Fehlermeldung:

SystemError: Das übergeordnete Modul '' ist nicht geladen, kann keine relativen .__ ausführen. einführen

Warum? Und wie funktioniert das?

49

da sich file1 und file2 im selben Verzeichnis befinden, benötigen Sie nicht einmal eine __init__.py-Datei. Wenn Sie sich vergrößern wollen, dann lassen Sie es dort.

So importieren Sie etwas in einer Datei im selben Verzeichnis

from file1 import f

sie müssen also nicht den relativen Pfad .file1 angeben, da sich diese im selben Verzeichnis befinden.

Befindet sich Ihre Hauptfunktion, Ihr Skript oder was auch immer, auf der die gesamte Anwendung ausgeführt wird, in einem anderen Verzeichnis, müssen Sie alles relativ zu dem Ausführungsort machen.

24
mrKelley

Das Starten von Modulen innerhalb eines Pakets als ausführbare Dateien ist eine bad-Praxis.

Wenn Sie etwas entwickeln, erstellen Sie entweder eine Bibliothek, die von anderen Programmen importiert werden soll. Daher ist es nicht sinnvoll, die Ausführung der Submodule direkt zuzulassen, oder Sie erstellen eine ausführbare Datei. In diesem Fall gibt es keinen Grund, sie zu einem Bestandteil zu machen eines Pakets.

Deshalb unterscheiden Sie in setup.py zwischen Paketen und Skripten. Die Pakete werden unter site-packages abgelegt, während die Skripts unter /usr/bin (oder einem ähnlichen Speicherort je nach Betriebssystem) installiert werden.

Meine Empfehlung ist daher folgendes Layout zu verwenden:

/
├── mydirectory
|    ├── __init__.py
|    ├── file1.py 
└── file2.py

Wo file2.pyfile1.py wie jeder andere Code importiert, der die Bibliothek mydirectory verwenden möchte, mit einem absoluten Import:

from mydirectory.file1 import f

Wenn Sie ein setup.py-Skript für das Projekt schreiben, listen Sie einfach mydirectory als Paket und file2.py als Skript auf, und alles funktioniert. Keine Notwendigkeit, mit sys.path zu arbeiten.

Wenn Sie aus irgendeinem Grund wirklich ein Submodul eines Pakets ausführen möchten, verwenden Sie den -m-Schalter:

python -m mydirectory.file1

Dadurch wird das gesamte Paket geladen und das Modul als Skript ausgeführt, sodass der relative Import erfolgreich ausgeführt werden kann.

Ich würde das persönlich vermeiden. Auch weil viele Leute nicht wissen, dass Sie dies tun können, und am Ende die gleiche Fehlermeldung erhalten wie Sie und dass das Paket defekt ist.


In Bezug auf die derzeit akzeptierte Antwort, die besagt, dass Sie einfach einen implicit relativen Import from file1 import f verwenden sollten, da sie funktionieren wird, da sie sich in demselben Verzeichnis befinden:

Das ist falsch

  • Es wird not nicht in Python3 funktionieren, wo implizite relative Importe nicht zulässig sind, und es wird sicherlich ein Fehler auftreten, wenn Sie ein file1-Modul installiert haben (da es statt Ihres Moduls importiert wird!).
  • Selbst wenn es funktioniert, wird der file1 nicht als Teil des mydirectory-Pakets angesehen. Dieses kann von Bedeutung sein. 

    Wenn beispielsweise file1pickle verwendet, ist der Name des Pakets wichtig für das ordnungsgemäße Laden/Entladen von Daten.

40
Bakuriu

Wenn Sie eine Python-Quelldatei starten, ist es verboten, eine andere Datei, die sich im aktuellen Paket befindet, mithilfe des relativen Imports zu importieren. 

In Dokumentation heißt es:

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

Wie @mrKelley sagte, müssen Sie in solchen Situationen den absoluten Import verwenden.

19
stalk
myproject/

mypackage
├── __init__.py
├── file1.py
├── file2.py 
└── file3.py

mymainscript.py

Beispiel zum Importieren von einer Datei in eine andere

#file1.py
from myproject import file2
from myproject.file3 import MyClass

Importieren Sie das Paketbeispiel in das Großskript

#mymainscript.py
import mypackage

https://docs.python.org/3/tutorial/modules.html#packages

https://docs.python.org/3/reference/import.html#regular-packages

https://docs.python.org/3/reference/simple_stmts.html#the-import-statement

https://docs.python.org/3/glossary.html#term-import-path

Die Variable sys.path ist eine Liste von Zeichenfolgen, die den Suchpfad des Interpreters für Module bestimmt. Es wird mit einem Standardpfad initialisiert, der aus der Umgebungsvariablen PYTHONPATH entnommen wird, oder aus einem integrierten Standardwert, wenn PYTHONPATH nicht festgelegt ist. Sie können es mit Standardlistenoperationen ändern:

import sys
sys.path.append('/ufs/guido/lib/python')
sys.path.insert(0, '/ufs/guido/myhaxxlib/python')

Das Einfügen am Anfang hat den Vorteil, dass bei Namenskonflikten sichergestellt wird, dass der Pfad vor anderen (auch eingebauten) gesucht wird.

0
The Demz