O que há de errado com as importações relativas em Python?

89

Atualizei recentemente as versões do pylint , um popular verificador de estilo Python.

Ele ficou balístico em todo o meu código, apontando lugares onde importo módulos no mesmo pacote, sem especificar o caminho completo do pacote.

A nova mensagem de erro é W0403.

W0403: Importação relativa% r, deve ser% r

Utilizado quando uma importação relativa ao diretório do pacote é detectada.


Exemplo

Por exemplo, se meus pacotes estiverem estruturados assim:

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

e no pacote de esponjas eu escrevo:

import icing

ao invés de

import cake.icing

Eu vou receber esse erro.


Embora eu entenda que nem todas as mensagens da Pylint são de igual importância e não tenho medo de descartá-las, não entendo por que essa prática é considerada uma péssima idéia.

Eu esperava que alguém pudesse explicar as armadilhas, para que eu pudesse melhorar meu estilo de codificação, em vez de (como eu atualmente planejo fazer) desativar esse aviso aparentemente falso.

Pensamento estranho
fonte

Respostas:

98

O problema import icingé que você não sabe se é uma importação absoluta ou relativa. icingpoderia um módulo no caminho do python ou um pacote no módulo atual. Isso é bastante irritante quando um pacote local tem o mesmo nome que um pacote de biblioteca padrão do python.

Você pode fazer o from __future__ import absolute_importque desativa completamente as importações relativas implícitas. É descrito, inclusive com essa justificativa sobre ambiguidade, no PEP 328 . Acredito que o Python 3000 tenha importações relativas implícitas desativadas completamente.

Você ainda pode fazer importações relativas, mas precisa fazê-las explicitamente, assim:

from . import icing
Winston Ewert
fonte
2
+1 especialmente para a solução de compromisso, que provavelmente é o caminho que devo seguir.
Oddthinking 04/08/12
2
Note que você também pode fazer em import .icingvez defrom . import icing
Jack
11
@ Jack, na verdade, eu não acho que você pode. A partir desta parte do PEP328 : importações relativo deve sempre usar from <> import; import <>é sempre absoluto. Obviamente, importações absolutas podem ser usadas from <> importomitindo os pontos iniciais. O motivo import .fooé proibido é porque depois import XXX.YYY.ZZZdisso XXX.YYY.ZZZé utilizável em uma expressão. Mas .moduleYnão é utilizável em uma expressão.
A.Wan
47

Existem algumas boas razões:

  1. As importações relativas quebram facilmente quando você move um módulo.

    Imagine que você tem um foo.bar, um foo.baze um bazmódulo no seu pacote. foo.barimportações foo.baz, mas usando uma importação relativa.

    Agora, se você mudar foo.barpara o barseu módulo, de repente está importando um diferente baz!

  2. As importações relativas são ambíguas. Mesmo sem mover o barmódulo no exemplo acima, um novo desenvolvedor que chega ao seu projeto pode ser perdoado por não perceber que bazé realmente o foo.bazlugar do bazpacote no nível raiz .

    Importações absolutas explicitam qual módulo está sendo usado. E, como import thisprega, explícito é melhor que implícito.

  3. O Python 3 desativou completamente as importações relativas implícitas; agora as importações são sempre interpretadas como absolutas, o que significa que no exemplo acima import bazsempre importará o módulo de nível superior. Você precisará usar a sintaxe de importação explícita ( from . import baz).

    Portar o exemplo do Python 2 para o 3 levaria a problemas inesperados, o uso de importações absolutas agora tornará seu código à prova de futuro.

Martijn Pieters
fonte
11
+1 para os nºs 2 e 3. Mas o número 1 deve ser comparado ao que acontece quando todo o diretório é movido (por exemplo, pressionado um nível).
Oddthinking 04/08/12