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.pyCela définit un package nommé
pkgcontenant les souspkg.main-pkg.stringmodules 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.stringmodule, et ce module est lié au nom"string"dans l'pkg.mainespace 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__.pyet string.pysont vides. main.pycontient 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
importle comportement de l 'importation absolue en utilisant unefrom __future__ import absolute_importdirective. 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 stringtrouvera toujours la version de la bibliothèque standard.
J'ai donc créé pkg/main2.py, identique main.pymais 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 stringtrouvera 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' printinstruction 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é stringcontenant uniquement un vide __init__.py- et au lieu d'émettre les importations en provenance main.py, je cd« d pour pkget 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?