Respondí una pregunta sobre importaciones absolutas en Python, que pensé que entendía basándome en la lectura el registro de cambios de Python 2.5 y acompañando ENERGÍA. Sin embargo, al instalar Python 2.5 e intentar crear un ejemplo del uso adecuado from __future__ import absolute_import
me doy cuenta de que las cosas no están tan claras.
Directamente del registro de cambios vinculado anteriormente, esta declaración resumió con precisión mi comprensión del cambio de importación absoluto:
Digamos que tiene un directorio de paquetes como este:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
Esto define un paquete llamado
pkg
que contiene elpkg.main
ypkg.string
submódulos.Considere el código en el módulo main.py. ¿Qué sucede si ejecuta la sentencia?
import string
? En Python 2.4 y anteriores, primero buscará en el directorio del paquete para realizar una importación relativa, encuentra pkg/string.py, importa el contenido de ese archivo como elpkg.string
módulo, y ese módulo está vinculado al nombre"string"
en elpkg.main
espacio de nombres del módulo.
Así que creé esta estructura de directorios exacta:
$ ls -R
.:
pkg/
./pkg:
__init__.py main.py string.py
__init__.py
y string.py
están vacíos. main.py
contiene el siguiente código:
import string
print string.ascii_uppercase
Como era de esperar, ejecutar esto con Python 2.5 falla con un 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'
Sin embargo, más adelante en el registro de cambios de 2.5, encontramos esto (énfasis añadido):
En Python 2.5, puede cambiar
import
el comportamiento de las importaciones absolutas usando unfrom __future__ import absolute_import
directiva. Este comportamiento de importación absoluta se convertirá en el predeterminado en una versión futura (probablemente Python 2.7). Una vez que las importaciones absolutas son las predeterminadas,import string
siempre encontrará la versión de la biblioteca estándar.
así creé pkg/main2.py
idéntico a main.py
pero con la futura directiva de importación adicional. Ahora se ve así:
from __future__ import absolute_import
import string
print string.ascii_uppercase
Ejecutar esto con Python 2.5, sin embargo… falla con un 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'
Esto contradice rotundamente la afirmación de que import string
voluntad siempre encuentre la versión std-lib con importaciones absolutas habilitadas. Además, a pesar de la advertencia de que las importaciones absolutas están programadas para convertirse en el “nuevo comportamiento predeterminado”, me encontré con este mismo problema al usar Python 2.7, con o sin el __future__
directiva:
$ 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'
así como Python 3.5, con o sin (suponiendo que el print
declaración se cambia en ambos archivos):
$ 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'
He probado otras variaciones de esto. En vez de string.py
he creado un módulo vacío, un directorio llamado string
que contiene sólo un vacío __init__.py
— y en lugar de emitir importaciones desde main.py
Tengo cd
Tendría que pkg
y ejecutar importaciones directamente desde el REPL. Ninguna de estas variaciones (ni una combinación de ellas) cambió los resultados anteriores. No puedo conciliar esto con lo que he leído sobre el __future__
directiva e importaciones absolutas.
Me parece que esto es fácilmente explicable por el seguimiento (Esto es de los documentos de Python 2, pero esta declaración permanece sin cambios en los mismos documentos para Python 3):
sys.ruta
(…)
Como se inicializó al iniciar el programa, el primer elemento de esta lista,
path[0]
, es el directorio que contiene el script que se usó para invocar al intérprete de Python. Si el directorio del script no está disponible (por ejemplo, si el intérprete se invoca de forma interactiva o si el script se lee desde la entrada estándar),path[0]
es la cadena vacía, que dirige a Python a buscar módulos en el directorio actual primero.
Entonces, ¿qué me estoy perdiendo? ¿Por qué el __future__
la declaración aparentemente no hace lo que dice, y ¿cuál es la resolución de esta contradicción entre estas dos secciones de documentación, así como entre el comportamiento descrito y el real?
Ver también: docs.python.org/2.5/whatsnew/pep-328.html
– drftymac
2 de diciembre de 2019 a las 22:52