Wie kann ich relative Importe in Python durchführen?

Lesezeit: 9 Minuten

Jorils Benutzeravatar
Joril

Stellen Sie sich diese Verzeichnisstruktur vor:

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

Ich codiere mod1und ich muss etwas aus importieren mod2. Wie soll ich es machen?

Ich habe es versucht from ..sub2 import mod2aber ich erhalte die Meldung “Attempted relative import in non-package”.

Ich habe herumgegoogelt, aber ich fand nur “sys.path Manipulation”-Hacks. Gibt es keinen sauberen Weg?


Alle meine __init__.pysind derzeit leer

Ich versuche dies, weil sub2 Klassen enthält, die von Unterpaketen gemeinsam genutzt werden (sub1, subXusw.).

Das Verhalten, nach dem ich suche, ist das gleiche wie in beschrieben PEP 366 (danke John B).

  • Ich empfehle, Ihre Frage zu aktualisieren, um deutlicher zu machen, dass Sie das in PEP 366 behandelte Problem beschreiben.

    – Johannes B

    16. September 2008 um 19:36 Uhr

  • Es ist eine langwierige Erklärung, aber überprüfen Sie hier: stackoverflow.com/a/10713254/1267156 Ich habe eine sehr ähnliche Frage beantwortet. Ich hatte das gleiche Problem bis gestern Abend.

    – Sevvy325

    23. Mai 2012 um 4:05 Uhr

  • Für diejenigen, die ein Modul laden möchten, das sich in einem beliebigen Pfad befindet, siehe hier: stackoverflow.com/questions/67631/…

    – Jewgeni Sergejew

    8. Juni 2014 um 6:29 Uhr

  • In diesem Zusammenhang wird Python 3 die Standardbehandlung von Importen so ändern, dass sie standardmäßig absolut ist. relative Importe müssen explizit angegeben werden.

    – Roß

    30. März 2015 um 23:28 Uhr

Benutzeravatar von John B
Johannes B

Das Problem besteht darin, dass Sie das Modul als „__main__“ ausführen, indem Sie mod1.py als Argument an den Interpreter übergeben.

Aus PEP 328:

Relative Importe verwenden das __name__-Attribut eines Moduls, um die Position dieses Moduls in der Pakethierarchie zu bestimmen. Wenn der Name des Moduls keine Paketinformationen enthält (z. B. auf „__main__“ gesetzt ist), werden relative Importe so aufgelöst, als ob das Modul ein Modul der obersten Ebene wäre, unabhängig davon, wo sich das Modul tatsächlich im Dateisystem befindet.

In Python 2.6 fügen sie die Möglichkeit hinzu, Module relativ zum Hauptmodul zu referenzieren. PEP 366 beschreibt die Veränderung.

Laut Nick Coghlan besteht die empfohlene Alternative darin, das Modul innerhalb des Pakets mit dem Schalter -m auszuführen.

  • Die empfohlene Alternative besteht darin, Module innerhalb von Paketen mit dem auszuführen -m wechseln, anstatt ihren Dateinamen direkt anzugeben.

    – ncoghlan

    23. Februar 2011 um 4:25 Uhr

  • Ich verstehe nicht: Wo ist hier die Antwort? Wie kann man Module in eine solche Verzeichnisstruktur importieren?

    – Tom

    29. September 2012 um 16:34 Uhr

  • @Tom: In diesem Fall wäre mod1 from sub2 import mod2. Führen Sie dann mod1 aus der App aus aus python -m sub1.mod1.

    – Xiong Tschamiow

    20. November 2012 um 6:06 Uhr

  • @XiongChiamiov: Bedeutet dies, dass Sie dies nicht tun können, wenn Ihr Python in eine Anwendung eingebettet ist, sodass Sie keinen Zugriff auf Python-Befehlszeilenschalter haben?

    – LarsH

    29. Januar 2013 um 16:58 Uhr

  • „Jeder scheint Ihnen sagen zu wollen, was Sie tun sollen, anstatt nur die Frage zu beantworten.“ Also, Gut. So erhalten Sie Hilfe beim Schreiben von Software sollen Sei! Wenn ich der guten Praxis widerspreche, Ich möchte es wissen.

    – jpmc26

    3. April 2019 um 3:52 Uhr

Hier ist die Lösung, die für mich funktioniert:

Ich mache die relativen Importe so from ..sub2 import mod2
und dann, wenn ich laufen will mod1.py dann gehe ich in das übergeordnete Verzeichnis von app und führen Sie das Modul mit dem python -m Schalter als aus python -m app.sub1.mod1.

Der eigentliche Grund, warum dieses Problem bei relativen Importen auftritt, ist, dass relative Importe funktionieren, indem sie die __name__ Eigenschaft des Moduls. Wenn das Modul direkt ausgeführt wird, dann __name__ ist eingestellt auf __main__ und es enthält keine Informationen über die Paketstruktur. Und deshalb beschwert sich Python über die relative import in non-package Fehler.

Wenn Sie also den Schalter -m verwenden, stellen Sie Python die Paketstrukturinformationen zur Verfügung, wodurch die relativen Importe erfolgreich aufgelöst werden können.

Ich bin bei relativen Importen oft auf dieses Problem gestoßen. Und nachdem ich alle vorherigen Antworten gelesen hatte, konnte ich immer noch nicht herausfinden, wie ich es auf saubere Weise lösen konnte, ohne dass ich Boilerplate-Code in alle Dateien einfügen musste. (Obwohl einige der Kommentare wirklich hilfreich waren, danke an @ncoghlan und @XiongChiamiov)

Ich hoffe, das hilft jemandem, der mit relativen Importproblemen zu kämpfen hat, denn das Durchlaufen von PEP macht wirklich keinen Spaß.

  • Beste Antwort IMHO: erklärt nicht nur, warum OP das Problem hatte, sondern findet auch einen Weg, es zu lösen ohne die Art und Weise zu ändern, wie seine Module Importe durchführen. Schließlich waren die relativen Importe von OP in Ordnung. Der Schuldige war der fehlende Zugriff auf äußere Pakete, wenn es direkt als Skript ausgeführt wurde, etwas -m wurde entwickelt, um zu lösen.

    – MestreLion

    7. November 2013 um 3:40 Uhr

  • Beachten Sie auch: Diese Antwort war 5 Jahre nach der Frage. Diese Funktionen waren damals noch nicht verfügbar.

    – Jeremy Kun

    1. April 2014 um 21:05 Uhr

  • Wenn Sie ein Modul aus demselben Verzeichnis importieren möchten, können Sie dies tun from . import some_module.

    – Rotareti

    16. September 2016 um 23:47 Uhr

  • Dies ist die Antwort, die mir geholfen hat, und sie hat mir auch geholfen, meine Gedanken auf Folgendes zu verdichten: Um ein Python-Skript auszuführen, das relative Importe enthält, muss ich das Skript währenddessen als Modul ausführen $ PWD ist sein übergeordnetes Verzeichnis wie $ python -m app.main. Zur Klarheit, $ python -m <main_directory>.<script_with_relative_imports>

    – Jesse H.

    15. Mai 2021 um 15:33 Uhr


main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. Sie laufen python main.py.
  2. main.py tut: import app.package_a.module_a
  3. module_a.py tut import app.package_b.module_b

Alternativ könnten 2 oder 3 verwenden: from app.package_a import module_a

Das wird so lange funktionieren, wie Sie haben app in Ihrem PYTHONPATH. main.py könnte dann überall sein.

Also schreibst du a setup.py das gesamte App-Paket und Unterpakete in die Python-Ordner des Zielsystems zu kopieren (installieren) und main.py in die Skriptordner des Zielsystems.

  • Ausgezeichnete Antwort. Gibt es eine Möglichkeit, auf diese Weise zu importieren, ohne das Paket in PYTHONPATH zu installieren?

    – auraham

    27. Juli 2012 um 16:34 Uhr

  • Empfohlene zusätzliche Lektüre: blog.habnab.it/blog/2013/07/21/python-packages-and-you

    – nosklo

    17. Oktober 2013 um 11:40 Uhr

  • dann müssen Sie eines Tages den Namen der App in test_app ändern. was würde passieren? Sie müssen alle Quellcodes ändern, app.package_b.module_b importieren –> test_app.package_b.module_b. das ist absolut SCHLECHTE Vorgehensweise… Und wir sollten versuchen, den relativen Import innerhalb des Pakets zu verwenden.

    – Spybdai

    16. Dezember 2016 um 11:30 Uhr


lesniks Benutzeravatar
Lesnik

“Guido betrachtet das Ausführen von Skripten innerhalb eines Pakets als Anti-Pattern” (abgelehnt
PEP-3122)

Ich habe so viel Zeit damit verbracht, eine Lösung zu finden, verwandte Beiträge hier auf Stack Overflow zu lesen und mir zu sagen: “Es muss einen besseren Weg geben!”. Anscheinend gibt es das nicht.

Benutzeravatar von Роман Арсеньев
Роман Арсеньев

Das ist zu 100% gelöst:

  • Anwendung/
    • main.py
  • Einstellungen/
    • local_settings.py

Einstellungen/local_setting.py in app/main.py importieren:

main.py:

import sys
sys.path.insert(0, "../settings")


try:
    from local_settings import *
except ImportError:
    print('No Import')

  • Danke! Alle Leute haben mich gezwungen, mein Skript anders auszuführen, anstatt mir zu sagen, wie ich es innerhalb des Skripts lösen soll. Aber ich musste den Code ändern, um ihn zu verwenden sys.path.insert(0, "../settings") und dann from local_settings import *

    – Vit Bernatik

    4. November 2016 um 20:22 Uhr


  • Können Sie bitte Ihre Antwort erläutern? Zum Beispiel, Warum funktioniert es? Wie funktioniert es? Was ist das Wesentliche? “Erklärung ist entscheidend für eine gute Antwort.”_. (Aber ***** ***** ***** ohne ***** ***** ***** “Bearbeiten:”, “Aktualisieren:” oder ähnliches – die Antwort sollte so aussehen, als wäre sie heute geschrieben worden)

    – Peter Mortensen

    28. März um 14:59 Uhr

Benutzeravatar von Peter Mortensen
Peter Mortensen

Erklärung der Antwort von nosklo mit Beispielen:

Hinweis: alle __init__.py Dateien sind leer.

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

app/package_a/fun_a.py

def print_a():
    print 'This is a function in dir package_a'

app/package_b/fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

main.py

from app.package_b import fun_b
fun_b.print_b()

Wenn du läufst python main.py es gibt zurück:

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • main.py macht: from app.package_b import fun_b
  • fun_b.py tut es from app.package_a.fun_a import print_a

also Datei im Ordner package_b verwendete Datei im Ordner package_a, was du willst. Rechts??

  • Danke! Alle Leute haben mich gezwungen, mein Skript anders auszuführen, anstatt mir zu sagen, wie ich es innerhalb des Skripts lösen soll. Aber ich musste den Code ändern, um ihn zu verwenden sys.path.insert(0, "../settings") und dann from local_settings import *

    – Vit Bernatik

    4. November 2016 um 20:22 Uhr


  • Können Sie bitte Ihre Antwort erläutern? Zum Beispiel, Warum funktioniert es? Wie funktioniert es? Was ist das Wesentliche? “Erklärung ist entscheidend für eine gute Antwort.”_. (Aber ***** ***** ***** ohne ***** ***** ***** “Bearbeiten:”, “Aktualisieren:” oder ähnliches – die Antwort sollte so aussehen, als wäre sie heute geschrieben worden)

    – Peter Mortensen

    28. März um 14:59 Uhr

Benutzeravatar von Peter Mortensen
Peter Mortensen

Verwenden:

def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

Ich verwende dieses Snippet, um Module aus Pfaden zu importieren.

  • Ich verwende dieses Snippet, kombiniert mit dem imp-Modul (wie hier erklärt [1]) mit großer Wirkung. [1]: stackoverflow.com/questions/1096216/…

    – Xiong Tschamiow

    16. Juli 2009 um 21:20 Uhr

  • Wahrscheinlich sollte sys.path.append(path) durch sys.path.insert(0, path) und sys.path ersetzt werden[-1] sollte durch sys.path ersetzt werden[0]. Andernfalls importiert die Funktion das falsche Modul, wenn bereits ein Modul mit demselben Namen im Suchpfad vorhanden ist. Wenn sich zB “some.py” im aktuellen Verzeichnis befindet, importiert import_path(“/imports/some.py”) die falsche Datei.

    – Alex Che

    16. Juni 2010 um 8:24 Uhr

  • Ich stimme zu! Manchmal haben andere relative Importe Vorrang. Verwenden Sie sys.path.insert

    – iElektrisch

    19. Juni 2010 um 7:13 Uhr

  • Wie würden Sie das Verhalten von from x import y (oder *) replizieren?

    – Leveske

    7. Dezember 2010 um 19:26 Uhr

  • Es ist nicht klar, bitte geben Sie die vollständige Nutzung dieses Skripts an, um das OP-Problem zu lösen.

    – Mrgloom

    24. September 2018 um 13:12 Uhr

1449020cookie-checkWie kann ich relative Importe in Python durchführen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy