Alterações na instrução de importação python3

177

Eu não entendo o seguinte de pep-0404

No Python 3, importações relativas implícitas dentro de pacotes não estão mais disponíveis - apenas importações absolutas e importações relativas explícitas são suportadas. Além disso, as importações em estrela (por exemplo, de x import *) são permitidas apenas no código no nível do módulo.

O que é uma importação relativa? Em que outros lugares a importação em estrela foi permitida no python2? Por favor, explique com exemplos.

balki
fonte

Respostas:

277

A importação relativa acontece sempre que você está importando um pacote em relação ao script / pacote atual.

Considere a seguinte árvore, por exemplo:

mypkg
├── base.py
└── derived.py

Agora, o seu derived.pyrequer algo de base.py. No Python 2, você pode fazer o seguinte (em derived.py):

from base import BaseThing

O Python 3 não suporta mais isso, pois não é explícito se você deseja o 'relativo' ou o 'absoluto' base. Em outras palavras, se houvesse um pacote Python baseinstalado no sistema, você pegaria o pacote errado.

Em vez disso, requer que você use importações explícitas que especificam explicitamente a localização de um módulo de maneira semelhante a caminho. Você derived.pyficaria assim:

from .base import BaseThing

O principal .diz 'importar basedo diretório do módulo'; em outras palavras, .basemapeia para ./base.py.

Da mesma forma, existe um ..prefixo que sobe na hierarquia de diretórios como ../(com ..modmapeamento para ../mod.py) e, em seguida, ...que sobe dois níveis ( ../../mod.py) e assim por diante.

Observe, no entanto, que os caminhos relativos listados acima eram relativos ao diretório em que o módulo atual ( derived.py) reside, não o diretório de trabalho atual.


A @BrenBarn já explicou o caso de importação em estrela. Para completar, terei que dizer o mesmo;).

Por exemplo, você precisa usar algumas mathfunções, mas você as usa apenas em uma única função. No Python 2, você tinha permissão para ser semi-preguiçoso:

def sin_degrees(x):
    from math import *
    return sin(degrees(x))

Observe que ele já dispara um aviso no Python 2:

a.py:1: SyntaxWarning: import * only allowed at module level
  def sin_degrees(x):

No código moderno do Python 2, você deve e no Python 3 você deve:

def sin_degrees(x):
    from math import sin, degrees
    return sin(degrees(x))

ou:

from math import *

def sin_degrees(x):
    return sin(degrees(x))
Michał Górny
fonte
14

Para importações relativas, consulte a documentação . Uma importação relativa é quando você importa de um módulo em relação à localização desse módulo, em vez de absolutamente de sys.path.

Quanto ao import *Python 2, permitiu importações em estrela nas funções, por exemplo:

>>> def f():
...     from math import *
...     print sqrt

Um aviso é emitido para isso no Python 2 (pelo menos nas versões recentes). No Python 3, não é mais permitido e você só pode fazer importações em estrela no nível superior de um módulo (não dentro de funções ou classes).

BrenBarn
fonte
6
Por que essa decisão foi tomada?
Dor
1
Meu palpite é que a ideia por trás disso é 'Explícito é melhor do que implícito'. do PEP20 - O Zen do Python. O ponto antes do módulo torna explícita a vinculação relativa / não relativa, resolvendo possíveis colisões de nomes. Embora 'Legibilidade conte'. sofre um pouco.
Pafnucy 3/09/15
2
Não, na verdade foi a decisão "oposta", "praticidade supera pureza". Isso foi necessário para otimizar o acesso às variáveis ​​locais dentro das funções, pois sem "import *", o compilador sempre sabe apenas analisando o código, quais variáveis ​​são locais e podem ser pesquisadas diretamente. De fato, as funções nem usam um dict para armazenamento local, mas uma matriz otimizada onde variáveis ​​obtêm índices únicos.
Veky
11

Para dar suporte ao Python 2 e Python 3, use importações relativas explícitas, como abaixo. Eles são relativos ao módulo atual. Eles foram suportados a partir do 2.5 .

from .sister import foo
from . import brother
from ..aunt import bar
from .. import uncle
Akseli Palén
fonte
14
import .brother me dá um erro de sintaxe inválido no Python 3.5. Isto é normal? Tenho o init .py no diretório que está em
Frikster
1
import .brotheré sintaxe inválida para python 2 e 3 #
Rodrigo E. Principe
@ RodrigoE.Principe e assim parece ser import ..uncle. Fixo. Oh, o que eu estava pensando ... provavelmente me distraí com os cavaleiros que dizem Ni!
Akseli Palén
4

Foi adicionado outro caso à resposta de Michał Górny:

Observe que as importações relativas são baseadas no nome do módulo atual. Como o nome do módulo principal é sempre " __main__", os módulos destinados ao uso como módulo principal de um aplicativo Python devem sempre usar importações absolutas.

Panfeng Li
fonte