J'ai répondu à une question concernant les importations absolues en Python, que je pensais comprendre en lisant le journal des modifications Python 2.5 et en accompagnant le PEP . Cependant, en installant Python 2.5 et en essayant de créer un exemple d'utilisation correcte from __future__ import absolute_import
, je me rends compte que les choses ne sont pas si claires.
Directement à partir du journal des modifications lié ci-dessus, cette déclaration a résumé avec précision ma compréhension du changement d'importation absolu:
Disons que vous avez un répertoire de packages comme celui-ci:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
Cela définit un package nommé
pkg
contenant les souspkg.main
-pkg.string
modules et .Considérez le code dans le module main.py. Que se passe-t-il s'il exécute l'instruction
import string
? Dans Python 2.4 et versions antérieures, il cherchera d'abord dans le répertoire du package pour effectuer une importation relative, trouve pkg / string.py, importe le contenu de ce fichier en tant quepkg.string
module, et ce module est lié au nom"string"
dans l'pkg.main
espace de noms du module.
J'ai donc créé cette structure de répertoires exacte:
$ ls -R
.:
pkg/
./pkg:
__init__.py main.py string.py
__init__.py
et string.py
sont vides. main.py
contient le code suivant:
import string
print string.ascii_uppercase
Comme prévu, son exécution avec Python 2.5 échoue avec 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'
Cependant, plus loin dans le changelog 2.5, nous trouvons ceci (emphase ajoutée):
Dans Python 2.5, vous pouvez changer
import
le comportement de l 'importation absolue en utilisant unefrom __future__ import absolute_import
directive. Ce comportement d'importation absolue deviendra le comportement par défaut dans une version future (probablement Python 2.7). Une fois que les importations absolues sont la valeur par défaut,import string
trouvera toujours la version de la bibliothèque standard.
J'ai donc créé pkg/main2.py
, identique main.py
mais avec la future directive d'importation supplémentaire. Cela ressemble maintenant à ceci:
from __future__ import absolute_import
import string
print string.ascii_uppercase
L'exécution de ceci avec Python 2.5, cependant ... échoue avec 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'
Cela contredit carrément la déclaration qui import string
trouvera toujours la version std-lib avec les importations absolues activées. De plus, malgré l'avertissement selon lequel les importations absolues sont programmées pour devenir le comportement "nouveau par défaut", j'ai rencontré le même problème en utilisant à la fois Python 2.7, avec ou sans la __future__
directive:
$ 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'
ainsi que Python 3.5, avec ou sans (en supposant que l' print
instruction soit modifiée dans les deux fichiers):
$ 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'
J'ai testé d'autres variantes de cela. Au lieu de string.py
, j'ai créé un module vide - un répertoire nommé string
contenant uniquement un vide __init__.py
- et au lieu d'émettre les importations en provenance main.py
, je cd
« d pour pkg
et exécuter les importations directement à partir du REPL. Aucune de ces variations (ni une combinaison d’entre elles) n’a changé les résultats ci-dessus. Je ne peux pas concilier cela avec ce que j'ai lu sur la __future__
directive et les importations absolues.
Il me semble que cela est facilement explicable par ce qui suit (cela provient de la documentation Python 2 mais cette déclaration reste inchangée dans la même documentation pour Python 3):
sys.path
(...)
Comme initialisé au démarrage du programme, le premier élément de cette liste,
path[0]
est le répertoire contenant le script qui a été utilisé pour appeler l'interpréteur Python. Si le répertoire de script n'est pas disponible (par exemple si l'interpréteur est appelé de manière interactive ou si le script est lu à partir de l'entrée standard),path[0]
est la chaîne vide, qui dirige Python vers les modules de recherche dans le répertoire courant en premier.
Alors qu'est-ce que je manque? Pourquoi la __future__
déclaration ne fait-elle apparemment pas ce qu'elle dit, et quelle est la résolution de cette contradiction entre ces deux sections de la documentation, ainsi qu'entre le comportement décrit et le comportement réel?