Importação relativa absoluta vs. explícita do módulo Python

90

Estou me perguntando sobre a maneira preferida de importar pacotes em um aplicativo Python. Eu tenho uma estrutura de pacote como esta:

project.app1.models
project.app1.views
project.app2.models

project.app1.viewsimportações project.app1.modelse project.app2.models. Há duas maneiras de fazer isso que vêm à mente.

Com importações absolutas:

import A.A
import A.B.B

ou com importações relativas explícitas, conforme apresentado no Python 2.5 com PEP 328 :

# explicit relative
from .. import A
from . import B

Qual é a maneira mais pítônica de fazer isso?

Daniel Hepper
fonte
os exemplos "relativos explícitos" são erros de sintaxe. As importações relativas devem estar na forma from _ import ..., então seus exemplos seriam from .. import Aefrom . import B
MestreLion
@MestreLion Boa captura, você está absolutamente certo! Eu atualizei minha pergunta de import ..Apara from .. import A. Notável que levou apenas 9 anos até que alguém notasse;)
Daniel Hepper

Respostas:

56

Importações absolutas. Do PEP 8:

Importações relativas para importações intra-embalagem são altamente desencorajadas. Sempre use o caminho do pacote absoluto para todas as importações. Mesmo agora que o PEP 328 [7] está totalmente implementado no Python 2.5, seu estilo de importações relativas explícitas é ativamente desencorajado; as importações absolutas são mais portáteis e geralmente mais legíveis.

As importações relativas explícitas são um bom recurso de linguagem (eu acho), mas não são tão explícitas quanto as importações absolutas. A forma mais legível é:

import A.A
import A.B.B

especialmente se você importar vários namespaces diferentes. Se você olhar para alguns projetos / tutoriais bem escritos que incluem importações de dentro de pacotes, eles geralmente seguem este estilo.

As poucas teclas extras que você toma para serem mais explícitas economizarão muito tempo para outros (e talvez você) no futuro, quando eles tentarem descobrir o seu namespace (especialmente se você migrar para 3.x, em que parte do pacote nomes mudaram).

Rafe Kettler
fonte
@Rafe, "veja alguns projetos bem escritos ..." alguma sugestão?
denis
@Denis: Rietveld é o projeto do próprio Guido van Rossum, então imagino que seja um bom lugar para procurar ( code.google.com/p/rietveld ). A biblioteca padrão do Python não é tão boa, grande parte desse código não segue as convenções.
Rafe Kettler
68
@Rafe: essa parte do PEP-8 está desatualizada, segundo Guido. mail.python.org/pipermail/python-dev/2010-October/104476.html
Brandon Rhodes
13
Essa declaração não está mais no PEP-8 agora. Ele agora afirma que as importações absolutas são recomendadas, mas as importações relativas são uma alternativa aceitável.
dano de
6
O problema que tenho com importações absolutas é quando uso um pacote dentro de outro pacote. No meu caso, está presente como um submódulo git. Neste caso, embora eu possa importar o pacote de nível superior, quaisquer pacotes abaixo deste não podem ser importados porque eles não conseguem encontrar seus próprios módulos com importações absolutas. Ao passo que, se eu usar as importações relativas nesse nível inferior, tudo funcionará.
davidA,
125

As importações relativas de Python não são mais fortemente desencorajadas, mas o uso de absolute_import é fortemente sugerido nesse caso.

Por favor, veja esta discussão citando o próprio Guido:

"Isso não é principalmente histórico? Até que a nova sintaxe de importação relativa fosse implementada, havia vários problemas com as importações relativas. A solução de curto prazo era recomendar não usá-las. A solução de longo prazo era implementar uma sintaxe inequívoca. Agora é hora de retirar a anti-recomendação. Claro, sem exagerar - ainda os considero um gosto adquirido; mas eles têm o seu lugar. "

O OP vincula corretamente o PEP 328 que diz:

Vários casos de uso foram apresentados, o mais importante deles é ser capaz de reorganizar a estrutura de grandes pacotes sem ter que editar subpacotes. Além disso, um módulo dentro de um pacote não pode ser facilmente importado sem importações relativas.

Veja também a pergunta quase duplicada Quando ou por que usar importações relativas em Python

Claro que ainda é uma questão de gosto. Embora seja mais fácil mover o código com importações relativas, isso também pode quebrar coisas inesperadamente; e renomear as importações não é tão difícil.

Para forçar o novo comportamento do PEP 328, use:

from __future__ import absolute_import

Neste caso, a importação relativa implícita não será mais possível (por exemplo import localfile, não funcionará mais, apenasfrom . import localfile ). Para um comportamento limpo e à prova de futuro, o uso de absolute_import é aconselhável.

Uma advertência importante é que, por causa do PEP 338 e PEP 366 , as importações relativas requerem que o arquivo python seja importado como um módulo - você não pode executar um file.py que tenha uma importação relativa ou você obterá umValueError: Attempted relative import in non-package .

Essa limitação deve ser levada em consideração ao avaliar a melhor abordagem. Guido é contra a execução de scripts de um módulo em qualquer caso:

Eu sou -1 nisso e em qualquer outra alteração proposta da máquina __main__. O único caso de uso parece ser a execução de scripts que vivem dentro de um diretório de módulo, que sempre vi como um antipadrão. Para me fazer mudar de ideia, você teria que me convencer de que não é.

Discussões exaustivas sobre o assunto podem ser encontradas no SO; ré. Python 3, isso é bastante abrangente:

Stefano
fonte
9
O Guido escreveu isso em 2010 e ainda está no PEP? Como podemos confiar nos PEPs se eles estão tão desatualizados?
Jabba
2
Os PEP são como as emendas dos EUA no sentido de que você pode alterar as coisas. Também há muitos PEPS rejeitados. PEPs são propostas. Eles podem ser aceitos, rejeitados ou se tornarem obsoletos, o que geralmente significa um novo PEP. O PEP 8 é um guia de estilo que pode ser modificado no local.
CppLearner
2
Estou confuso sobre a parte "um módulo dentro de um pacote não pode importar-se facilmente ...". Eu nunca tinha ouvido falar sobre a importação de módulos antes.
matiascelasco
2
Um exemplo possível @matiascelasco: se você tiver foo / bar.py e foo / baz.py, mas também baz.py em outro lugar. Se você deseja importar foo.baz do bar, você pode querer ter certeza do que está importando, por exemplo. import .baz- esta é apenas uma situação simplista de muitas situações semelhantes descritas no PEP.
Stefano
Sua resposta não distingue claramente a mudança em permiti-los. Importações relativas implícitas nunca devem ser usadas, mas importações relativas explícitas podem ser usadas. O parente implícito foi removido do Python3.
ninMonkey
33

As importações relativas não apenas deixam você livre para renomear seu pacote posteriormente sem alterar dezenas de importações internas, mas também tive sucesso com elas na solução de certos problemas envolvendo coisas como importações circulares ou pacotes de namespace, porque eles não enviam Python "de volta para o top "para iniciar a busca pelo próximo módulo novamente a partir do namespace de nível superior.

Brandon Rhodes
fonte
4
Este é o estilo desencorajado de acordo com o guia de estilo Python. Eles atrapalham a legibilidade severamente e não valem a percepção de "conveniência" a que você alude. Se você precisar usar importações relativas para resolver um problema, você está fazendo isso errado.
Rafe Kettler
14
Observe seu comentário (de Brandon Rhodes) na outra resposta, com um link mostrando que não é mais desencorajado.
Jon Coombs
1
@RafeKettler pode explicar como você usaria importações absolutas em um pacote que está incluído em outro pacote? As importações absolutas falharão dentro do pacote interno porque não sabem sobre o novo nível superior. As importações relativas continuam a funcionar. Provavelmente, alguém poderia argumentar que o pacote não deveria ser aninhado dentro de outro em primeiro lugar, mas alguns códigos devem ser reutilizáveis ​​e isso acontece muito. Muito código reutilizado não é empacotado para o público e, portanto, não é fornecido como um pacote separado, então métodos ad-hoc como importação / submódulos VCS acabam sendo usados ​​em seu lugar
davidA 01 de
3
@meowsqueak Eu concordo, alguns pacotes não são facilmente instaláveis ​​(eles não estão no pip, você não quer usar python setup.py installou python setup.py developpor qualquer motivo), nesses casos eu bifurco o código-fonte e o adiciono como um submódulo git. Quando esses pacotes usam importações absolutas em seu próprio nome de pacote, suas importações falham. A única solução é usar importações relativas explícitas. Isso é o que deve ser encorajado, eu acho.
CMCDragonkai