it-swarm-eu.dev

Wie mache ich relative Importe in Python?

Stellen Sie sich diese Verzeichnisstruktur vor:

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

Ich codiere mod1 und muss etwas aus mod2 importieren. Wie soll ich das machen

Ich habe from ..sub2 import mod2 ausprobiert, erhalte aber die Meldung "Versuchter relativer Import in Nicht-Paket".

Ich habe herumgegoogelt, aber nur "sys.path manipulation" -Hacks gefunden. Gibt es nicht einen sauberen Weg?


Bearbeiten: Alle meine __init__.py sind derzeit leer

Edit2: Ich versuche dies zu tun, weil 2 Klassen enthält, die über Unterpakete (sub1, subX, etc.) geteilt werden.

Edit3: Das Verhalten, nach dem ich suche, ist dasselbe wie in PEP 366 (danke John B) beschrieben.

498
Joril

Jeder scheint Ihnen sagen zu wollen, was Sie tun sollten, anstatt nur die Frage zu beantworten.

Das Problem ist, dass Sie das Modul als '__main__' ausführen, indem Sie die Datei mod1.py als Argument an den Interpreter übergeben.

Von PEP 328 :

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

In Python 2.6 können sie Module relativ zum Hauptmodul referenzieren. PEP 366 beschreibt die Änderung.

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

320
John B
main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. Sie führen python main.py aus.
  2. main.py macht: import app.package_a.module_a
  3. module_a.py macht import app.package_b.module_b

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

Das funktioniert, solange Sie app in Ihrem PYTHONPATH haben. main.py könnte dann überall sein.

Sie schreiben also einen setup.py, um das gesamte App-Paket und die Unterpakete in die python -Ordner des Zielsystems und main.py in die Skriptordner des Zielsystems zu kopieren (zu installieren).

121
nosklo

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

Ich führe die relativen Importe als from ..sub2 import mod2 aus. Wenn ich dann mod1.py ausführen möchte, gehe ich zum übergeordneten Verzeichnis von app und führe das Modul mit dem python aus. -m wechsle als python -m app.sub1.mod1.

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

Wenn Sie also den Schalter -m verwenden, geben Sie die Paketstrukturinformationen an Python weiter, wodurch die relativen Importe erfolgreich aufgelöst werden können.

Ich habe dieses Problem oft beim relativen Importieren festgestellt. Und nachdem ich alle vorherigen Antworten gelesen hatte, war ich immer noch nicht in der Lage, herauszufinden, wie ich es auf saubere Weise lösen kann, ohne dass in allen Dateien Code für die Auflistung von Stichwörtern eingefügt werden muss. (Obwohl einige der Kommentare dank @ncoghlan und @XiongChiamiov wirklich hilfreich waren)

Hoffe, das hilft jemandem, der mit relativen Importproblemen kämpft, denn das Durchlaufen von PEP macht wirklich keinen Spaß.

118
Pankaj

"Guido betrachtet das Ausführen von Skripten in einem Paket als Anti-Pattern" (abgelehnt PEP-3122 )

Ich habe so viel Zeit damit verbracht, nach einer Lösung zu suchen, verwandte Posts hier auf Stack Overflow zu lesen und mir zu sagen: "Es muss einen besseren Weg geben!". Sieht so aus, als gäbe es das nicht.

48
lesnik

Dies ist zu 100% gelöst:

  • app /
    • main.py
  • die Einstellungen/
    • local_setings.py

Importiere settings/local_setting.py in app/main.py:

main.py:

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


try:
    from local_settings import *
except ImportError:
    print('No Import')
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 benutze dieses Snippet, um Module von Pfaden zu importieren, hoffe das hilft

24
iElectric

erklärung von nosklo's mit Beispielen beantworten

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 Sie $ python main.py ausführen, wird Folgendes zurückgegeben:

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 macht from app.package_a.fun_a import print_a

also Datei im Ordner package_b Verwendete Datei im Ordner package_a, was Sie wollen. Richtig??

21
suhailvs

Dies ist leider ein sys.path-Hack, aber es funktioniert ganz gut.

Ich bin auf dieses Problem mit einer anderen Ebene gestoßen: Ich hatte bereits ein Modul mit dem angegebenen Namen, aber es war das falsche Modul.

was ich tun wollte, war das folgende (das Modul, von dem ich arbeitete, war Modul3):

mymodule\
   __init__.py
   mymodule1\
      __init__.py
      mymodule1_1
   mymodule2\
      __init__.py
      mymodule2_1


import mymodule.mymodule1.mymodule1_1  

Beachten Sie, dass ich mymodule bereits installiert habe, in meiner Installation jedoch nicht "mymodule1".

und ich würde einen ImportError bekommen, weil er versuchte, von meinen installierten Modulen zu importieren.

Ich habe versucht, ein sys.path.append zu machen, und das hat nicht funktioniert. Was funktioniert hat war ein sys.path.insert

if __== '__main__':
    sys.path.insert(0, '../..')

So eine Art Hack, aber es hat alles geklappt! Denken Sie also daran, wenn Sie möchten, dass Ihre Entscheidung andere Pfade überschreibt, müssen Sie sys.path.insert (0, Pfadname) verwenden, damit es funktioniert! Dies war ein sehr frustrierender Knackpunkt für mich, viele Leute sagen, sie sollten die Funktion "Anhängen" an sys.path verwenden, aber das funktioniert nicht, wenn Sie bereits ein Modul definiert haben (ich finde es sehr seltsames Verhalten).

12
Garrett Berg

Lassen Sie mich dies hier nur zu meiner eigenen Referenz setzen. Ich weiß, dass es kein guter Python Code ist, aber ich brauchte ein Skript für ein Projekt, an dem ich arbeitete, und ich wollte das Skript in ein scripts Verzeichnis stellen.

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
10
milkypostman

Wie @EvgeniSergeev in den Kommentaren zum OP sagt, können Sie Code aus einer .py -Datei an einem beliebigen Ort importieren:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

Dies wird aus dieser SO Antwort entnommen.

8
LondonRob

Schauen Sie sich http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports an. Du könntest es tun

from .mod1 import stuff
4
mossplix

From Python doc ,

In Python 2.5 können Sie das Verhalten des Imports mithilfe einer from __future__ import absolute_import -Direktive in absolute Importe ändern. Dieses absolute Importverhalten wird in einer zukünftigen Version zum Standard (wahrscheinlich Python 2.7). Sobald der absolute Import die Standardeinstellung ist, findet import string immer die Version der Standardbibliothek. Es wird empfohlen, dass Benutzer anfangen, absolute Importe so weit wie möglich zu verwenden. Daher ist es vorzuziehen, from pkg import string in Ihren Code zu schreiben

2
jung rhew

Zusätzlich zu dem, was John B gesagt hat, scheint es hilfreich zu sein, die Variable __package__ zu setzen, anstatt __main__ zu ändern, was andere Dinge vermasseln könnte. Aber soweit ich es testen konnte, funktioniert es nicht ganz so, wie es sollte.

Ich habe das gleiche Problem und weder PEP 328 noch PEP 366 lösen das Problem vollständig, da beide am Ende des Tages den Kopf des Pakets in sys.path enthalten müssen, soweit ich das verstehen kann.

Ich sollte auch erwähnen, dass ich nicht gefunden habe, wie die Zeichenfolge formatiert werden soll, die in diese Variablen eingefügt werden soll. Ist es "package_head.subfolder.module_name" oder was?

1
Gabriel

Ich fand es einfacher, die Umgebungsvariable "PYTHONPATH" auf den obersten Ordner zu setzen:

bash$ export PYTHONPATH=/PATH/TO/APP

dann:

import sub1.func1
#...more import

natürlich ist PYTHONPATH "global", aber es hat mir noch keine Probleme bereitet.

1
Andrew_1510