Cosa c'è di sbagliato con le importazioni relative in Python?


89

Di recente ho aggiornato le versioni di pylint , un popolare verificatore di stili Python.

È diventato balistico in tutto il mio codice, indicando i luoghi in cui importare i moduli nello stesso pacchetto, senza specificare il percorso completo del pacchetto.

Il nuovo messaggio di errore è W0403.

W0403: L'importazione relativa% r, dovrebbe essere% r

Utilizzato quando viene rilevata un'importazione relativa alla directory del pacchetto.


Esempio

Ad esempio, se i miei pacchetti sono strutturati in questo modo:

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

e nel pacchetto spugna scrivo:

import icing

invece di

import cake.icing

Riceverò questo errore.


Anche se capisco che non tutti i messaggi di Pylint sono della stessa importanza e non ho paura di respingerli, non capisco perché una tale pratica sia considerata una cattiva idea.

Speravo che qualcuno potesse spiegare le insidie, in modo da poter migliorare il mio stile di programmazione piuttosto che (come attualmente sto pianificando di fare) disattivando questo avviso apparentemente falso.

Risposte:


98

Il problema import icingè che non sai se si tratta di un'importazione assoluta o di un'importazione relativa. icingpotrebbe un modulo nel percorso di Python o un pacchetto nel modulo corrente. Questo è piuttosto fastidioso quando un pacchetto locale ha lo stesso nome di un pacchetto di libreria standard di Python.

Si può fare from __future__ import absolute_importche disattiva del tutto le importazioni relative implicite. È descritto, anche con questa giustificazione sull'ambiguità, in PEP 328 . Credo che Python 3000 abbia completamente implicito l'importazione relativa implicita.

Puoi ancora effettuare importazioni relative, ma devi eseguirle in modo esplicito, in questo modo:

from . import icing

2
+1 soprattutto per la soluzione di compromesso, che probabilmente è la strada da percorrere.
Pensando in modo strano il

2
Nota che puoi anche fare import .icinginvece difrom . import icing
Jack

11
@Jack in realtà non penso che tu possa. Da questa parte di PEP328 : le importazioni relative devono sempre essere utilizzate from <> import; import <>è sempre assoluto. Naturalmente, le importazioni assolute possono essere utilizzate from <> importomettendo i punti iniziali. La ragione import .fooè proibito è perché dopo import XXX.YYY.ZZZallora XXX.YYY.ZZZè utilizzabile in un'espressione. Ma .moduleYnon è utilizzabile in un'espressione.
A.Wan

47

Ci sono alcuni buoni motivi:

  1. Le importazioni relative si interrompono facilmente quando si sposta un modulo.

    Immagina di avere a foo.bar, a foo.baze un bazmodulo nel tuo pacchetto. foo.barimportazioni foo.baz, ma utilizzando un'importazione relativa.

    Ora, se si dovesse spostare foo.bara bar, il modulo improvvisamente sta importando un diverso baz!

  2. Le importazioni relative sono ambigue. Anche senza spostarsi all'interno del barmodulo nell'esempio sopra, un nuovo sviluppatore che arriva al tuo progetto potrebbe essere perdonato per non aver realizzato che bazè in realtà foo.bazinvece del bazpacchetto a livello di root .

    Le importazioni assolute rendono esplicito quale modulo viene utilizzato. E come import thispredica, esplicito è meglio di implicito.

  3. Python 3 ha disabilitato del tutto le importazioni relative implicite; le importazioni sono ora sempre interpretate come assolute, il che significa che nell'esempio precedente import bazimporterà sempre il modulo di livello superiore. Dovrai invece utilizzare la sintassi di importazione esplicita ( from . import baz).

    Portare l'esempio da Python 2 a 3 porterebbe quindi a problemi imprevisti, l'uso delle importazioni assolute renderà il tuo codice a prova di futuro.


11
+1 per # 2 e # 3. Ma # 1 deve essere compensato da ciò che accade quando l'intera directory viene spostata (ad esempio, abbassata di livello).
Pensando in modo strano il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.