¿Qué hace from __future__ import absolute_import realmente?

| | | | | | | | |

He respondido una pregunta sobre importaciones absolutas en Python, que pensé que entendía basándome en leer el registro de cambios de Python 2.5 y PEP. Sin embargo, al instalar Python 2.5 e intentar crear un ejemplo del uso adecuado de from __future__ import absolute_import, me doy cuenta de que las cosas no están tan claras.

Directamente desde el registro de cambios vinculado anteriormente, esto La 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 pkg.main y submódulos pkg.string.

Considere el código en el módulo main.py. ¿Qué sucede si ejecuta la instrucción import string? En Python 2.4 y versiones 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 el módulo pkg.string, y ese módulo está vinculado al nombre "string" en los nombres del módulo pkg.main ritmo.

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 se esperaba, ejecutándolo con Python 2.5 falla con un AttributeError:

$ python2.5 pkg/main.py Rastreo (última llamada más reciente): Archivo "pkg/main.py", línea 2 , en <módulo> print string.ascii_uppercase AttributeError: el objeto "módulo" no tiene atributo "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 el comportamiento de import" a importaciones absolutas usando una directiva from __future__ import absolute_import. 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 sean las predeterminadas, importar cadena siempre encontrará la versión de la biblioteca estándar.

Por lo tanto, 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 Rastreo (última llamada más reciente): Archivo "pkg/main2.py", línea 3, en < ;módulo> print string.ascii_uppercase AttributeError: el objeto "módulo" no tiene atributo "ascii_uppercase" 

Esto contradice rotundamente la afirmación de que importar cadena 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 el mismo problema al usar Python 2.7, con o sin la directiva __future__:

$ python2.7 pkg/main.py Rastreo (última llamada más reciente): Archivo "pkg/main.py", línea 2, en <módulo>, print string.ascii_uppercase AttributeError: objeto "módulo" no tiene atributo "ascii_uppercase" $ python2.7 pkg/main2.py Rastreo (última llamada más reciente): archivo "pkg/main2.py", línea 3, en <módulo>, cadena de impresión.ascii_uppercase AttributeError: objeto "módulo" no tiene el atributo "ascii_uppercase" 

así como Python 3.5, con o sin (suponiendo que la instrucción print se cambie en ambos archivos):

$ python3.5 pkg/main.py Rastreo (última llamada más reciente): Archivo "pkg/main.py", línea 2, en <módulo> print(string.ascii_uppercase) AttributeError: module "string " no tiene atributo "ascii_uppercase" $ python3.5 pkg/main2.py Trac eback (última llamada más reciente): Archivo "pkg/main2.py", línea 3, en <module> print(string.ascii_uppercase) AttributeError: el módulo "string" no tiene atributo "ascii_uppercase" 

He probado otras variaciones de esto. En lugar de string.py, he creado un módulo vacío, un directorio llamado string que contiene solo un __init__.py vacío, y en su lugar de emitir importaciones desde main.py, tengo cd"d en pkg y ejecuto importaciones directamente desde REPL. Ninguna de estas variaciones (ni una combinación de ellos) cambió los resultados anteriores. No puedo conciliar esto con lo que he leído sobre la directiva __future__ y las importaciones absolutas.

Me parece que esto es fácilmente explicable por lo siguiente (esto es de los documentos de Python 2 pero este permanece sin cambios en los mismos documentos para Python 3):

sys.path

(...)

Como se inicializó al iniciar el programa, el primer elemento de esta lista, ruta[0], es el directorio que contiene el script que se usó para invocar al intérprete de Python. Si el director del script y 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 primero el directorio actual.

Entonces, ¿qué me estoy perdiendo? ¿Por qué la instrucción __future__ aparentemente no hace lo que dice y cuál es la resolución de esta contradicción entre estas dos secciones de la documentación, así como entre el comportamiento descrito y el real?

Shop

Learn programming in R: courses

$

Best Python online courses for 2022

$

Best laptop for Fortnite

$

Best laptop for Excel

$

Best laptop for Solidworks

$

Best laptop for Roblox

$

Best computer for crypto mining

$

Best laptop for Sims 4

$

Latest questions

NUMPYNUMPY

psycopg2: insert multiple rows with one query

12 answers

NUMPYNUMPY

How to convert Nonetype to int or string?

12 answers

NUMPYNUMPY

How to specify multiple return types using type-hints

12 answers

NUMPYNUMPY

Javascript Error: IPython is not defined in JupyterLab

12 answers


Wiki

Python OpenCV | cv2.putText () method

numpy.arctan2 () in Python

Python | os.path.realpath () method

Python OpenCV | cv2.circle () method

Python OpenCV cv2.cvtColor () method

Python - Move item to the end of the list

time.perf_counter () function in Python

Check if one list is a subset of another in Python

Python os.path.join () method