I odpowiedział na pytanie dotyczące bezwzględnych importu w Pythonie, i pomyślałem, zrozumiałem, na podstawie odczytu z Python 2.5 changelog i towarzyszące PEP . Jednak po zainstalowaniu Pythona 2.5 i próbie stworzenia przykładu prawidłowego użycia from __future__ import absolute_import
, zdaję sobie sprawę, że sprawy nie są takie jasne.
Prosto z dziennika zmian połączonego powyżej, to stwierdzenie dokładnie podsumowało moje rozumienie absolutnej zmiany importu:
Powiedzmy, że masz taki katalog pakietów:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
Definiuje pakiet o nazwie
pkg
zawierający podmodułypkg.main
ipkg.string
.Rozważ kod w module main.py. Co się stanie, jeśli wykona instrukcję
import string
? W Pythonie 2.4 i wcześniejszych, najpierw zajrzy do katalogu pakietu, aby wykonać względny import, znajdzie pkg / string.py, zaimportuje zawartość tego pliku jakopkg.string
moduł i ten moduł zostanie powiązany z nazwą"string"
wpkg.main
przestrzeni nazw modułu.
Stworzyłem więc dokładną strukturę katalogów:
$ ls -R
.:
pkg/
./pkg:
__init__.py main.py string.py
__init__.py
i string.py
są puste. main.py
zawiera następujący kod:
import string
print string.ascii_uppercase
Zgodnie z oczekiwaniami, uruchomienie tego w Pythonie 2.5 kończy się niepowodzeniem z 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'
Jednak dalej w dzienniku zmian 2.5 znajdujemy to (podkreślenie dodane):
W Pythonie 2.5 możesz przełączyć
import
zachowanie na bezwzględne importowanie za pomocąfrom __future__ import absolute_import
dyrektywy. To zachowanie importu absolutnego stanie się domyślnym w przyszłej wersji (prawdopodobnie Python 2.7). Gdy import bezwzględny jest domyślny,import string
zawsze znajdzie wersję biblioteki standardowej.
Stworzyłem w ten sposób pkg/main2.py
, identyczny, main.py
ale z dodatkową przyszłą dyrektywą importową. Teraz wygląda to tak:
from __future__ import absolute_import
import string
print string.ascii_uppercase
Jednak uruchomienie tego w Pythonie 2.5 ... kończy się niepowodzeniem z 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'
To dość kategorycznie zaprzecza oświadczenie, że import string
będzie zawsze znaleźć wersję STD-lib z włączonym import bezwzględne. Co więcej, pomimo ostrzeżenia, że import absolutny ma stać się „nowym domyślnym” zachowaniem, napotkałem ten sam problem, używając zarówno Pythona 2.7, z __future__
dyrektywą lub bez niej :
$ 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'
a także Python 3.5, z lub bez (zakładając zmianę print
instrukcji w obu plikach):
$ 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'
Przetestowałem inne odmiany tego. Zamiast string.py
Ja stworzyłem pusty module - katalog o nazwie string
zawierającej tylko pusta __init__.py
- i zamiast wydawania importu z main.py
mam cd
„d, aby pkg
i uruchomić import bezpośrednio z REPL. Żadna z tych odmian (ani ich kombinacja) nie zmieniła powyższych wyników. Nie mogę tego pogodzić z tym, co przeczytałem o __future__
dyrektywie i bezwzględnym imporcie.
Wydaje mi się, że można to łatwo wyjaśnić w następujący sposób (pochodzi z dokumentacji Pythona 2, ale ta instrukcja pozostaje niezmieniona w tych samych dokumentach dla Pythona 3):
sys.path
(...)
Zgodnie z inicjalizacją podczas uruchamiania programu, pierwszą pozycją na tej liście
path[0]
jest katalog zawierający skrypt, który został użyty do wywołania interpretera Pythona. Jeśli katalog skryptu nie jest dostępny (np. Jeśli interpreter jest wywoływany interaktywnie lub jeśli skrypt jest czytany ze standardowego wejścia),path[0]
jest to pusty łańcuch, który kieruje Pythona do wyszukiwania modułów w bieżącym katalogu w pierwszej kolejności.
Więc czego mi brakuje? Dlaczego __future__
stwierdzenie pozornie nie robi tego, co mówi, i jakie jest rozwiązanie tej sprzeczności między tymi dwoma rozdziałami dokumentacji, a także między opisanym a rzeczywistym zachowaniem?