HOWTO · Python

Lösen Sie versuchten relativen Import ohne bekanntes übergeordnetes Paket in Python

Dieses Tutorial beschreibt, wie man ImportError löst und mit relativem Import in Python umgeht.

Auf dieser Seite

ImportError: attempted relative import with no known parent package bedeutet, dass Python ein Modul ohne den Paketkontext ausführt, den sein relativer Import mit führendem Punkt benötigt. Meist lässt sich das beheben, indem Sie das Modul über sein Paket starten oder einen absoluten Import verwenden, der zur Projektstruktur passt. Eine __init__.py-Datei allein gibt einem direkt gestarteten Skript kein übergeordnetes Paket.

Warum Python diesen ImportError auslöst

Ein relativer Import wie from .helpers import format_name geht vom Paket des aktuellen Moduls aus. Python kennt dieses Paket, wenn das Modul als Teil eines Pakets importiert wird. Eine direkt gestartete Datei heißt dagegen __main__ und hat im Allgemeinen keinen Paketnamen. Deshalb kann python path/to/module.py fehlschlagen, obwohl das Paketverzeichnis und die importierte Datei vorhanden sind.

Auch die Syntax muss ein gültiger from-Import sein. import .module_name ist keine gültige Python-Syntax. Verwenden Sie stattdessen etwa from . import module_name oder from .module_name import function_name. Ein führender Punkt bedeutet „relativ zu diesem Paket“ und nicht „im selben Verzeichnis suchen, unabhängig davon, wie diese Datei gestartet wurde“.

Das Modul im Paketkontext starten

Legen Sie die Dateien für ein Paket namens myPackage in einem gemeinsamen Projektverzeichnis ab: IError/myPackage/__init__.py, IError/myPackage/myNewPackage.py und IError/myPackage/main.py. In main.py kann der relative Import from .myNewPackage import createSingleDict lauten. Führen Sie das Modul mit python -m myPackage.main aus dem Verzeichnis IError aus, das myPackage enthält. Die Option -m weist Python an, das Modul als Teil seines Pakets zu finden und auszuführen. So ist für den relativen Import ein übergeordnetes Paket bekannt.

Starten Sie myPackage/main.py nicht über seinen Dateipfad, wenn die Datei einen relativen Import verwendet. Führen Sie auch __init__.py nicht direkt aus: Python verwendet diese Datei zur Initialisierung des Pakets, wenn das Paket importiert wird. Sie ist nicht der Einstiegspunkt des Pakets.

Einen absoluten Import verwenden, wenn er zum Projekt passt

Ein absoluter Import benennt ein Modul aus dem Import-Suchpfad, zum Beispiel from myPackage.myNewPackage import createSingleDict. Er eignet sich, wenn das Projekt bereits Paketimporte ab der Paketwurzel verwendet und diese Wurzel über sys.path verfügbar ist, etwa weil Sie Python vom Projektverzeichnis aus starten oder das Paket in der Umgebung installieren.

Wählen Sie einen Importstil, der zur Anwendung und zur Art passt, wie Sie sie starten. Ein absoluter Import behebt keinen Paketnamen, den Python nicht finden kann. Prüfen Sie, ob das angegebene Paket in der aktuellen Umgebung importierbar ist.

Paketstruktur und Arbeitsverzeichnis prüfen

Prüfen Sie, ob das im Import angegebene Verzeichnis tatsächlich das Paket ist, das Sie laden möchten, ob der Moduldateiname zum Import passt und ob Sie Python vom erwarteten Projektverzeichnis aus starten. Im obigen Beispiel ist IError das Arbeitsverzeichnis, nicht IError/myPackage; der Befehl lautet python -m myPackage.main. Liegt das Paket tiefer in der Verzeichnisstruktur, nehmen Sie alle Paketbestandteile in den Modulpfad auf. Starten Sie beispielsweise python -m project.tools.runner aus dem Verzeichnis, das project enthält.

Ein reguläres Paket enthält häufig eine __init__.py-Datei. Python unterstützt jedoch auch Namespace-Pakete, wenn die Verzeichnisstruktur dafür geeignet ist. Entscheidend für die Diagnose ist, wie das Modul ausgeführt wird: Eine Datei kann in einem Paketverzeichnis liegen und beim direkten Start trotzdem keinen Paketkontext haben. Prüfen Sie außerdem den aktiven Interpreter und die Umgebung, wenn sich das Importverhalten in Terminal, IDE und Test-Runner unterscheidet.

Die Lösung mit einem Minimalbeispiel überprüfen

Dieses eigenständige Beispiel erstellt ein kleines Paket in einem temporären Verzeichnis und startet anschließend dessen Einstiegsmodul mit python -m. Führen Sie das Beispiel mit Python aus; es gibt den von der importierten Funktion zurückgegebenen Wert aus.

from pathlib import Path
import subprocess
import sys
import tempfile

with tempfile.TemporaryDirectory() as temporary_directory:
    project = Path(temporary_directory)
    package = project / "myPackage"
    package.mkdir()
    (package / "__init__.py").write_text("", encoding="utf-8")
    (package / "myNewPackage.py").write_text(
        'def createSingleDict(name, value):\n'
        '    return {"name": name, "value": value}\n',
        encoding="utf-8",
    )
    (package / "main.py").write_text(
        "from .myNewPackage import createSingleDict\n"
        'print(createSingleDict("Jacob", 25))\n',
        encoding="utf-8",
    )
    result = subprocess.run(
        [sys.executable, "-m", "myPackage.main"],
        cwd=project,
        check=True,
        capture_output=True,
        text=True,
    )
    print(result.stdout, end="")

Das Arbeitsverzeichnis des Befehls ist die temporäre Projektwurzel. Daher kann Python myPackage finden und main als Paketmodul laden. Wenn Sie dieses Muster übernehmen, muss der Modulpfad nach -m zu den Ordnern unterhalb des Verzeichnisses passen, aus dem Sie Python starten.

Untermodulnamen bei Bedarf aus init.py exportieren

Exporte auf Paketebene sind eine optionale Komfortfunktion. Sollen Aufrufer ausgewählte Namen wie myPackage.createSingleDict verwenden können, fügen Sie from .myNewPackage import createSingleDict in __init__.py ein. Beim Import von myPackage steht die Funktion dann über das Paket zur Verfügung. Bei mehreren Modulen kann __init__.py ausgewählte Namen aus jedem Modul importieren, zum Beispiel mit from .otherPackage import printName.

Diese Exporte bestimmen, welche Namen bequem über den Paketnamensraum verfügbar sind. Sie geben einer Datei, die direkt gestartet wird, keinen Paketkontext. Beheben Sie diese Ursache, indem Sie das Modul als Paket ausführen oder einen passenden absoluten Import verwenden.