Cosa fa effettivamente da __future__ import absolute_import?

| | | | | | | | |

Ho risposto a una domanda sull'importazione assoluta in Python, che pensavo di aver capito leggendo il log delle modifiche di Python 2.5 e il relativo PEP. Tuttavia, dopo aver installato Python 2.5 e aver tentato di creare un esempio di utilizzo corretto di da __future__ import absolute_import, mi rendo conto che le cose non sono così chiare.

Direttamente dal changelog collegato sopra, questo istruzione riassume accuratamente la mia comprensione della modifica assoluta dell'importazione:

Supponiamo che tu abbia una directory di pacchetti come questa:

pkg/pkg/__init__.py pkg/main.py pkg/string.py 

Questo definisce un pacchetto chiamato pkg contenente pkg.main e pkg.string sottomoduli.

Considera il codice nel modulo main.py. Cosa succede se esegue l'istruzione import string? In Python 2.4 e precedenti, esso prima cercherà nella directory del pacchetto per eseguire un'importazione relativa, troverà pkg/string.py, importerà il contenuto di quel file come modulo pkg.string e quel modulo è legato al nome "string" nei nomi del modulo pkg.main pace.

Così ho creato questa esatta struttura di directory:

$ ls -R .: pkg/ ./pkg: __init__.py main.py string .py 

__init__.py e string.py sono vuoti. main.py contiene il seguente codice:

import string print string.ascii_uppercase 

Come previsto, eseguendo questo con Python 2.5 fallisce con un AttributeError:

$ python2.5 pkg/main.py Traceback (ultima chiamata più recente): File "pkg/main.py", riga 2 , in <modulo> print string.ascii_uppercase AttributeError: l'oggetto "module" non ha attributo "ascii_uppercase" 

Tuttavia, più avanti nel changelog 2.5, troviamo questo (enfasi aggiunta):

In Python 2.5, puoi cambiare il comportamento di import su importazioni assolute usando una direttiva from __future__ import absolute_import. Questo comportamento di importazione assoluta diventerà l'impostazione predefinita in una versione futura (probabilmente Python 2.7). Una volta che le importazioni assolute sono l'impostazione predefinita, stringa di importazione troverà sempre la versione della libreria standard.

Ho così creato pkg/main2.py, identico a main.py ma con la futura direttiva import aggiuntiva. Ora appare così:

from __future__ import absolute_import import string print string.ascii_uppercase 

Eseguendo questo con Python 2.5, tuttavia... fallisce con un AttributeError:

$ python2.5 pkg/main2.py Traceback (ultima chiamata più recente): File "pkg/main2.py", riga 3, in < ;modulo> print string.ascii_uppercase AttributeError: l'oggetto "module" non ha attributo "ascii_uppercase" 

Questo contraddice abbastanza chiaramente l'affermazione che import string sempre strong> trova la versione std-lib con le importazioni assolute abilitate. Inoltre, nonostante l'avviso che le importazioni assolute sono programmate per diventare il comportamento "nuovo predefinito", ho riscontrato lo stesso problema utilizzando entrambi Python 2.7, con o senza la direttiva __future__:

$ python2.7 pkg/main.py Traceback (ultima chiamata più recente): File "pkg/main.py", riga 2, in <module> print string.ascii_uppercase AttributeError: oggetto "module" non ha attributo "ascii_uppercase" $ python2.7 pkg/main2.py Traceback (chiamata più recente ultima): File "pkg/main2.py", riga 3, in <module> print string.ascii_uppercase AttributeError: oggetto "module" non ha alcun attributo "ascii_uppercase" 

così come Python 3.5, con o senza (supponendo che l'istruzione print sia modificata in entrambi i file):

$ python3.5 pkg/main.py Traceback (ultima chiamata più recente): File "pkg/main.py", riga 2, in <module> print(string.ascii_uppercase) AttributeError: module "string " non ha attributo "ascii_uppercase" $ python3.5 pkg/main2.py Trac eback (ultima chiamata più recente): File "pkg/main2.py", riga 3, in <module> print(string.ascii_uppercase) AttributeError: il modulo "string" non ha attributo "ascii_uppercase" 

Ho testato altre varianti di questo. Invece di string.py, ho creato un modulo vuoto -- una directory denominata string contenente solo un __init__.py vuoto -- e invece di emettere importazioni da main.py, ho cd"d a pkg ed eseguo le importazioni direttamente dal REPL. Nessuna di queste variazioni (né una combinazione di questi) ha cambiato i risultati sopra. Non riesco a conciliarlo con ciò che ho letto sulla direttiva __future__ e sulle importazioni assolute.

Mi sembra che questo sia facilmente spiegabile da il seguente (questo proviene dai documenti Python 2 ma questo rimane invariata negli stessi documenti per Python 3):

sys.path

(...)

Come inizializzato all'avvio del programma, il primo elemento di questa lista, path[0], è la directory contenente lo script che è stato utilizzato per invocare l'interprete Python. y non è disponibile (ad es. se l'interprete viene invocato in modo interattivo o se lo script viene letto dallo standard input), path[0] è la stringa vuota, che indirizza Python a cercare i moduli nel prima la directory corrente.

Allora cosa mi sto perdendo? Perché l'istruzione __future__ sembra non fare ciò che dice, e qual è la risoluzione di questa contraddizione tra queste due sezioni della documentazione, così come tra il comportamento descritto e quello effettivo?

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