Was ist los mit relativen Importen in Python?

89

Ich habe kürzlich Versionen von Pylint aktualisiert , einem beliebten Python-Stilprüfer.

Es ist in meinem gesamten Code ballistisch und zeigt Stellen auf, an denen ich Module in dasselbe Paket importiere, ohne den vollständigen Paketpfad anzugeben.

Die neue Fehlermeldung lautet W0403.

W0403: Der relative Import% r sollte% r sein

Wird verwendet, wenn ein Import relativ zum Paketverzeichnis erkannt wird.


Beispiel

Zum Beispiel, wenn meine Pakete so aufgebaut sind:

/cake
  /__init__.py
  /icing.py
  /sponge.py
/drink

und in der Schwammpackung schreibe ich:

import icing

Anstatt von

import cake.icing

Ich werde diesen Fehler bekommen.


Obwohl ich verstehe, dass nicht alle Pylint-Nachrichten gleich wichtig sind und ich keine Angst habe, sie zu verwerfen, verstehe ich nicht, warum eine solche Praxis als schlechte Idee angesehen wird.

Ich hatte gehofft, jemand könnte die Fallstricke erklären, damit ich meinen Codierungsstil verbessern könnte, anstatt (wie ich derzeit vorhabe) diese scheinbar unechte Warnung auszuschalten.

Merkwürdig
quelle

Antworten:

97

Das Problem import icingist, dass Sie nicht wissen, ob es sich um einen absoluten oder einen relativen Import handelt. icingkönnte ein Modul im Pfad von Python oder ein Paket im aktuellen Modul sein. Dies ist ziemlich ärgerlich, wenn ein lokales Paket denselben Namen wie ein Python-Standardbibliothekspaket hat.

Sie können damit from __future__ import absolute_importimplizite relative Importe insgesamt deaktivieren. In PEP 328 wird dies auch mit dieser Begründung zur Mehrdeutigkeit beschrieben . Ich glaube, Python 3000 hat implizite relative Importe komplett abgeschaltet.

Sie können weiterhin relative Importe durchführen, müssen diese jedoch explizit wie folgt ausführen:

from . import icing
Winston Ewert
quelle
2
+1 vor allem für die Kompromisslösung, die wahrscheinlich der Weg ist, den ich gehen sollte.
Oddthinking
2
Beachten Sie, Sie können auch import .icinganstelle vonfrom . import icing
Jack
11
@ Jack, ich glaube nicht, dass du das kannst. Aus diesem Teil von PEP328 : Relative Importe müssen immer verwendet werden from <> import. import <>ist immer absolut. Natürlich können absolute Importe verwendet from <> importwerden, indem die führenden Punkte weggelassen werden. Der Grund import .fooist verboten, weil import XXX.YYY.ZZZdanach XXX.YYY.ZZZin einem Ausdruck verwendet werden kann. Ist .moduleYaber in einem Ausdruck nicht verwendbar.
Am
48

Es gibt ein paar gute Gründe:

  1. Relative Importe brechen leicht ab, wenn Sie ein Modul verschieben.

    Stellen Sie sich vor, Sie haben ein foo.bar, ein foo.bazund ein bazModul in Ihrem Paket. foo.barImporte foo.baz, aber mit einem relativen Import.

    Nun, wenn Sie sich zu bewegen waren foo.barzu bar, Ihr Modul plötzlich importiert eine andere baz!

  2. Relative Importe sind nicht eindeutig. Selbst barwenn Sie sich im obigen Beispiel nicht durch das Modul bewegen , könnte es einem neuen Entwickler, der zu Ihrem Projekt kommt, verzeihen, dass er nicht weiß, dass bazes sich tatsächlich um ein Paket auf foo.bazRoot-Ebene handelt baz.

    Absolute Importe machen deutlich, welches Modul verwendet wird. Und als import thisPrediger ist explizit besser als implizit.

  3. Python 3 hat implizite relative Importe insgesamt deaktiviert. Importe werden jetzt immer als absolut interpretiert, was bedeutet, dass im obigen Beispiel import bazimmer das Modul der obersten Ebene importiert wird. Sie müssen stattdessen die explizite Importsyntax verwenden ( from . import baz).

    Die Portierung des Beispiels von Python 2 auf 3 würde daher zu unerwarteten Problemen führen. Wenn Sie jetzt absolute Importe verwenden, ist Ihr Code zukunftssicher.

Martijn Pieters
quelle
10
+1 für # 2 und # 3. Aber # 1 muss gegen das verrechnet werden, was passiert, wenn das gesamte Verzeichnis verschoben wird (z. B. eine Ebene nach unten gedrückt).
Oddthinking