Python-Verpackung für relative Importe

71

Zunächst einmal: Es tut mir leid, ich weiß, dass es viele Fragen zu relativen Importen gab, aber ich habe einfach keine Lösung gefunden. Wenn möglich möchte ich folgendes Verzeichnislayout verwenden:

myClass/
    __init__.py
    test/
        demo.py
        benchmark.py
        specs.py
    src/
        __init__.py
        myClass.py

Jetzt sind meine Fragen:

  • Wie importieren die Testdateien aus dem Paket myClass.py ordnungsgemäß?

  • Wie würden Sie das Paket von außen importieren, vorausgesetzt, Sie nehmen myClass als Submodul in libs / myClass oder include / myClass?

Bisher konnte ich dafür keine elegante Lösung finden. Soweit ich Guidos Entscheidung verstehe , sollte es möglich sein, dies zu tun, from ..src import myClassaber dies wird einen Fehler machen:

ValueError: Attempted relative import in non-package

Das sieht so aus, als würde myClass nicht als Paket behandelt. Lesen Sie die Dokumente :

Die Dateien __init__.py sind erforderlich, damit Python die Verzeichnisse als Pakete enthaltend behandelt.

Es scheint, dass mir etwas fehlt, das angibt, wo sich die Skripte des Pakets befinden. Soll ich .pth verwenden?

eerne
quelle
6
@Brent Newey, ja, Sie haben Recht, relative Importe scheinen ein fortlaufendes Thema zu sein, und nachdem ich einige Antworten gelesen hatte, verspürte ich immer noch den Drang, meine Situation spezifisch zu beschreiben. Nachdem dieses q auf dem # Python-IRC-Kanal angezeigt wurde, empfahlen einige Leute die Verwendung einer flachen Verzeichnisstruktur: "Viele Leute widersetzen sich der Art und Weise, wie Python Verzeichnisse und Dateien für semantische Namespace-Informationen verwenden möchte. Es ist am besten, nur nachzugeben und zu tun was Python will. " jcalderone.livejournal.com/39794.html
eerne
8
Könnte jemand einen Link zu einigen realen Paketen mit beispielhaftem Verzeichnislayout oder nach Konventionen bereitstellen? (idealerweise auf Github)
Eerne
1
Gibt es __init__.pyim testVerzeichnis? ValueError: Attempted relative import in non-packagekönnte damit zusammenhängen.
JFS
Das Lesen der offiziellen Dokumentation hat mir sehr geholfen! docs.python.org/3/reference/…
Kavin Raju S

Antworten:

42

ValueError: Attempted relative import in non-package

Bedeutet, dass Sie versuchen, den relativen Import in dem Modul zu verwenden, das kein Paket ist. Sein Problem mit der Datei, die dies hatfrom ... import Anweisung enthält, und nicht mit der Datei, die Sie importieren möchten.

Wenn Sie beispielsweise in Ihren Tests relative Importe durchführen, sollten Sie Ihre Tests als Teil Ihres Pakets festlegen. Das heisst

  1. Hinzufügen __init__.pyZum Test /
  2. Führen Sie sie von einem externen Skript aus, z. B. von Nosetests

Wenn Sie etwas als ausführen python myClass/test/demo.py, funktionieren relative Importe auch nicht, da Sie das Demomodul nicht als Paket ausführen . Relative Importe erfordern, dass das Modul, das sie verwendet, selbst entweder als Paketmodul from myClass.test.demo import blablaoder mit relativem Import importiert wird.

Daniel Kluev
quelle
28

Nachdem ich letzte Nacht stundenlang gesucht hatte, fand ich die Antwort auf relative Importe in Python !! Oder zumindest eine einfache Lösung. Der beste Weg, dies zu beheben, besteht darin, die Module von einem anderen Modul aufrufen zu lassen. Angenommen, Sie möchten demo.pyimportieren myClass.py. Im myClassOrdner im Stammverzeichnis der Unterpakete muss eine Datei vorhanden sein, die die beiden anderen aufruft. Soweit ich weiß, wird das Arbeitsverzeichnis immer berücksichtigt. __main__Wenn Sie den Import demo.pymit dem demo.pySkript testen , wird dieser Fehler angezeigt. Um zu veranschaulichen:

Ordnerhierarchie:

myClass/
    main.py #arbitrary name, can be anything
    test/
        __init__.py
        demo.py
    src/
        __init__.py
        myClass.py

myClass.py:

def randomMaths(x):
    a = x * 2
    y = x * a
    return y

demo.py:

from ..src import myClass

def printer():
    print(myClass.randomMaths(42))

main.py:

import test.demo

demo.printer()

Wenn Sie demo.pyim Interpreter ausgeführt werden, wird ein Fehler generiert, beim Ausführen main.pyjedoch nicht. Es ist ein wenig verworren, aber es funktioniert: D.

Sevvy325
quelle
3
Ich verwende Python 2.7 und habe nur den obigen Code zum Laufen gebracht, indem ich drei Dinge getan habe. Zuerst habe ich auf der Ebene, auf der sich main.py befindet, a hinzugefügt __init__.py. Zweitens habe ich demo.printer () in geändert test.demo.printer(). Drittens habe ich das Verzeichnis über der main.py gewechselt und bin gelaufen python -m myClass.main. Ansonsten war dies eine sehr hilfreiche Antwort für mich. :)
Paul
0

Intra-Package-Referenzen beschreiben, wie man myClassvon test/*. Um das Paket von außen zu importieren, sollten Sie seinen Pfad zur PYTHONPATHUmgebungsvariablen hinzufügen , bevor Sie die Importer-Anwendung sys.pathausführen , oder vor dem Import im Code auflisten.

Warum from ..src import myClassfehlschlägt: Wahrscheinlich srchandelt es sich nicht um ein Python-Paket, das Sie nicht von dort importieren können. Sie sollten es wie oben beschrieben zum Python-Pfad hinzufügen.

Khachik
quelle
Relative Importe werden ständig durchgeführt. Viele Pakete enthalten kleinere Unterpakete und sind auf relative Importe angewiesen. Das OP fragt nicht, wie externe Pakete referenziert werden sollen. Er fragt, wie auf ein anderes Unterpaket innerhalb eines Pakets verwiesen werden soll.
Cstrutton