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 PEP. Cependant, lors de l'installation de Python 2.5 et de la tentative de création d'un exemple d'utilisation correcte de depuis __future__ import absolute_import
, je me rends compte que les choses ne sont pas si claires.
Droit du journal des modifications lié ci-dessus, ceci déclaration résume 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 lepkg.main
etpkg.string
sous-modules.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 va d'abord chercher dans le répertoire du package pour effectuer une importation relative, trouve pkg/string.py, importe le contenu de ce fichier en tant que modulepkg.string
, et ce module est lié au nom"string"
dans les noms des modulespkg.main
rythme.
J'ai donc créé cette structure de répertoire 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, l'exécution avec Python 2.5 échoue avec une AttributeError
:
$ python2.5 pkg/main.py Traceback (dernier appel le plus récent) : Fichier "pkg/main.py", ligne 2 , dans <module> print string.ascii_uppercase AttributeError : l'objet "module" n'a pas d'attribut "ascii_uppercase"
Cependant, plus loin dans le journal des modifications 2.5, nous trouvons ceci (nous soulignons) :
Dans Python 2.5, vous pouvez basculer le comportement de
import
vers des importations absolues à l'aide d'une directivefrom __future__ import absolute_import
. Ce comportement d'importation absolue deviendra la valeur par défaut dans une future version (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. Il ressemble maintenant à ceci :
from __future__ import absolute_import import string print string.ascii_uppercase
L'exécution avec Python 2.5, cependant... échoue avec un AttributeError
:
$ python2.5 pkg/main2.py Traceback (appel le plus récent en dernier) : fichier "pkg/main2.py", ligne 3, dans < ;module> print string.ascii_uppercase AttributeError : l'objet "module" n'a pas d'attribut "ascii_uppercase"
Cela contredit assez catégoriquement l'affirmation selon laquelle importer la chaîne
sera toujours recherchez la version std-lib avec les importations absolues activées. De plus, malgré l'avertissement que les importations absolues sont programmées pour devenir le "nouveau comportement par défaut", j'ai rencontré ce même problème en utilisant Python 2.7, avec ou sans la directive __future__
:
$ python2.7 pkg/main.py Traceback (dernier appel le plus récent) : Fichier "pkg/main.py", ligne 2, dans <module> print string.ascii_uppercase AttributeError : objet "module" n'a pas d'attribut "ascii_uppercase" $ python2.7 pkg/main2.py Traceback (appel le plus récent en dernier) : fichier "pkg/main2.py", ligne 3, dans <module> print string.ascii_uppercase AttributeError : objet "module" n'a pas d'attribut "ascii_uppercase"
ainsi que Python 3.5, avec ou sans (en supposant que l'instruction print
est modifiée dans les deux fichiers) :
$ python3.5 pkg/main.py Traceback (dernier appel le plus récent) : Fichier "pkg/main.py", ligne 2, dans <module> print(string.ascii_uppercase) AttributeError : module "string " n'a pas d'attribut "ascii_uppercase" $ python3.5 pkg/main2.py Trac eback (appel le plus récent en dernier) : fichier "pkg/main2.py", ligne 3, dans <module> print(string.ascii_uppercase) AttributeError : le module "string" n'a pas d'attribut "ascii_uppercase"
J'ai testé d'autres variantes de ceci. Au lieu de string.py
, j'ai créé un module vide -- un répertoire nommé string
contenant seulement un __init__.py
vide -- et à la place d'émettre des importations depuis main.py
, j'ai cd
"d vers pkg
et j'exécute les importations directement depuis le REPL. Aucune de ces variantes (ni une combinaison d'entre eux) a changé les résultats ci-dessus. Je ne peux pas concilier cela avec ce que j'ai lu sur la directive __future__
et les importations absolues.
Il me semble que cela est facilement explicable par ce qui suit (ceci provient de la documentation Python 2 mais ceci l'instruction 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 invoquer l'interpréteur Python. Si le directeur du script y 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 pour rechercher des modules dans le répertoire courant en premier.
Alors qu'est-ce que je rate ? Pourquoi l'instruction __future__
ne fait 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 ?