Tenho respondido uma pergunta sobre as importações absolutos em Python, que eu pensei que eu entendi com base na leitura do changelog Python 2.5 e acompanhando PEP . No entanto, ao instalar o Python 2.5 e tentar criar um exemplo de uso adequado from __future__ import absolute_import
, percebo que as coisas não são tão claras.
Diretamente do changelog acima, esta declaração resumiu com precisão minha compreensão da mudança absoluta de importação:
Digamos que você tenha um diretório de pacotes como este:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
Isso define um pacote chamado
pkg
contendo os subpkg.main
-pkg.string
módulos e .Considere o código no módulo main.py. O que acontece se a instrução for executada
import string
? No Python 2.4 e versões anteriores, ele procurará primeiro no diretório do pacote uma importação relativa, localiza pkg / string.py, importa o conteúdo desse arquivo comopkg.string
módulo e esse módulo é vinculado ao nome"string"
nopkg.main
espaço de nome do módulo.
Então, eu criei essa estrutura de diretório exata:
$ ls -R
.:
pkg/
./pkg:
__init__.py main.py string.py
__init__.py
e string.py
estão vazios. main.py
contém o seguinte código:
import string
print string.ascii_uppercase
Como esperado, executar isso com o Python 2.5 falha com um AttributeError
:
$ python2.5 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
No entanto, mais adiante no changelog 2.5, encontramos o seguinte (ênfase adicionada):
No Python 2.5, você pode mudar
import
o comportamento para importações absolutas usando umafrom __future__ import absolute_import
diretiva. Esse comportamento de importação absoluta se tornará o padrão em uma versão futura (provavelmente Python 2.7). Uma vez que as importações absolutas são o padrão,import string
sempre encontrará a versão da biblioteca padrão.
Criei assim pkg/main2.py
, idêntico a, main.py
mas com a futura diretiva de importação adicional. Agora, fica assim:
from __future__ import absolute_import
import string
print string.ascii_uppercase
Executar isso com o Python 2.5, no entanto ... falha com um AttributeError
:
$ python2.5 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
Este bastante categoricamente contradiz a afirmação de que import string
irá sempre encontrar a versão std-lib com as importações absolutos habilitado. Além do mais, apesar do aviso de que importações absolutas estão agendadas para se tornar o comportamento "novo padrão", encontrei o mesmo problema usando o Python 2.7, com ou sem a __future__
diretiva:
$ python2.7 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
$ python2.7 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
bem como Python 3.5, com ou sem (assumindo que a print
instrução foi alterada nos dois arquivos):
$ python3.5 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'
$ python3.5 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'
Eu testei outras variações disso. Em vez de string.py
, eu criei um módulo vazio - um diretório chamado string
contendo apenas um vazio __init__.py
- e em vez de emitir as importações a partir main.py
, eu tenho cd
'd para pkg
e executar as importações diretamente do REPL. Nenhuma dessas variações (nem uma combinação delas) alterou os resultados acima. Não consigo conciliar isso com o que li sobre a __future__
diretiva e as importações absolutas.
Parece-me que isso é facilmente explicável pelo seguinte (isso é dos documentos do Python 2, mas essa declaração permanece inalterada nos mesmos documentos do Python 3):
sys.path
(...)
Conforme inicializado na inicialização do programa, o primeiro item desta lista
path[0]
, é o diretório que contém o script usado para chamar o interpretador Python. Se o diretório do script não estiver disponível (por exemplo, se o intérprete for chamado interativamente ou se o script for lido a partir da entrada padrão),path[0]
será a string vazia, que instrui o Python a pesquisar os módulos no diretório atual primeiro.
Então o que estou perdendo? Por que a __future__
declaração aparentemente não faz o que diz e qual é a resolução dessa contradição entre essas duas seções da documentação, bem como entre o comportamento descrito e o real?