Ho risposto a una domanda relativa alle importazioni assolute in Python, che pensavo di aver capito basandomi sulla lettura del log delle modifiche di Python 2.5 e sull'accompagnamento di PEP . Tuttavia, dopo aver installato Python 2.5 e aver tentato di creare un esempio di utilizzo corretto from __future__ import absolute_import
, mi rendo conto che le cose non sono così chiare.
Direttamente dal log delle modifiche sopra citato, questa affermazione ha riassunto accuratamente la mia comprensione del cambiamento di importazione assoluto:
Supponiamo che tu abbia una directory dei pacchetti come questa:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
Questo definisce un pacchetto chiamato
pkg
contenente ipkg.main
epkg.string
sottomoduli.Considera il codice nel modulo main.py. Cosa succede se esegue l'istruzione
import string
? In Python 2.4 e precedenti, cercherà prima nella directory del pacchetto di eseguire un'importazione relativa, trova pkg / string.py, importa il contenuto di quel file comepkg.string
modulo e quel modulo è associato al nome"string"
nellopkg.main
spazio dei nomi del modulo.
Quindi 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, l'esecuzione di questo con Python 2.5 non riesce 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'
Tuttavia, più avanti nel log delle modifiche 2.5, troviamo questo (enfasi aggiunta):
In Python 2.5, puoi cambiare
import
il comportamento in importazioni assolute usando unafrom __future__ import absolute_import
direttiva. Questo comportamento di importazione assoluta diventerà il valore predefinito in una versione futura (probabilmente Python 2.7). Una volta che le importazioni assolute sono predefinite,import string
troverà sempre la versione della libreria standard.
Ho così creato pkg/main2.py
, identico main.py
ma con la futura direttiva sulle importazioni aggiuntiva. Ora sembra così:
from __future__ import absolute_import
import string
print string.ascii_uppercase
L'esecuzione con Python 2.5, tuttavia ... non riesce 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'
Ciò contraddice in modo piuttosto netto l'affermazione che import string
troverà sempre la versione std-lib con le importazioni assolute abilitate. Inoltre, nonostante l'avvertimento che le importazioni assolute sono programmate per diventare il comportamento "nuovo predefinito", ho riscontrato questo stesso problema utilizzando sia Python 2.7, con o senza la __future__
direttiva:
$ 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'
così come Python 3.5, con o senza (supponendo che l' print
istruzione sia cambiata in entrambi i file):
$ 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'
Ho testato altre varianti di questo. Invece di string.py
, ho creato un modulo vuoto - una directory di nome string
che contiene solo un vuoto __init__.py
- e, invece di emettere importazioni da main.py
, ho cd
'd per pkg
ed eseguire le importazioni direttamente dal REPL. Nessuna di queste variazioni (né una combinazione di esse) ha modificato i risultati sopra. Non posso conciliare questo con ciò che ho letto sulla __future__
direttiva e sulle importazioni assolute.
Mi sembra che ciò sia facilmente spiegabile come segue (questo proviene dai documenti di Python 2 ma questa affermazione rimane invariata negli stessi documenti di Python 3):
sys.path
(...)
Come inizializzato all'avvio del programma, il primo elemento di questo elenco
path[0]
, è la directory contenente lo script utilizzato per richiamare l'interprete Python. Se la directory di script non è disponibile (ad es. Se l'interprete viene richiamato in modo interattivo o se lo script viene letto dall'input standard),path[0]
è la stringa vuota che indirizza Python a cercare prima i moduli nella directory corrente.
Quindi cosa mi sto perdendo? Perché la __future__
dichiarazione sembra non fare ciò che dice, e qual è la soluzione di questa contraddizione tra queste due sezioni della documentazione, nonché tra il comportamento descritto e quello reale?