Co właściwie robi funkcja __future__ import absolute_import?

| | | | | | | | |

Udało mi się odpowiedzieć na pytanie dotyczące bezwzględnego importu w Pythonie, które, jak sądziłem, zrozumiałem na podstawie czytania dziennik zmian Pythona 2.5 i towarzyszący mu PEP. Jednak po zainstalowaniu Pythona 2.5 i próbie stworzenia przykładu prawidłowego użycia z __future__ import absolute_import, zdaję sobie sprawę, że sprawy nie są takie jasne.

Prosto z powyższego dziennika zmian, to oświadczenie dokładnie podsumowało moje zrozumienie bezwzględnej zmiany importu:

Powiedzmy, że masz taki katalog pakietów:

pkg/pkg/__init__.py pkg/main.py pkg/string.py 

To definiuje pakiet o nazwie pkg zawierający pkg.main i pkg.string.

Rozważ kod w module main.py. Co się stanie, jeśli wykona on instrukcję import string? W Pythonie 2.4 i wcześniejszych najpierw zajrzy do katalogu pakietu, aby wykonać import względny, znajdzie plik pkg/string.py, zaimportuje zawartość tego pliku jako moduł pkg.string i ten moduł zostanie powiązany z nazwą "string" w nazwach modułu pkg.main pace.

Więc stworzyłem dokładnie taką 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 nie powiedzie się z AttributeError:

$ python2.5 pkg/main.py Traceback (ostatnie wywołanie ostatnie): Plik "pkg/main.py", wiersz 2 , w <module> print string.ascii_uppercase AttributeError: obiekt "module" nie ma atrybutu "ascii_uppercase" 

Jednak w dalszej części dziennika zmian 2.5 znajdujemy to (podkreślenie dodane):

W Pythonie 2.5 możesz zmienić zachowanie import na import bezwzględny za pomocą dyrektywy from __future__ import absolute_import. To zachowanie importu bezwzględnego stanie się domyślne w przyszłą wersję (prawdopodobnie Python 2.7). Gdy importy bezwzględne będą wartościami domyślnymi, ciąg importu zawsze znajdzie wersję standardowej biblioteki.

W ten sposób stworzyłem pkg/main2.py, identyczny z main.py, ale z dodatkową przyszłą dyrektywą importu. Teraz wygląda to tak:

from __future__ import absolute_import import string print string.ascii_uppercase 

Uruchomienie tego w Pythonie 2.5, jednak... kończy się niepowodzeniem z AttributeError:

$ python2.5 pkg/main2.py Traceback (ostatnie wywołanie ostatnie): Plik "pkg/main2.py", wiersz 3, w < ;moduł> print string.ascii_uppercase AttributeError: obiekt "module" nie ma atrybutu "ascii_uppercase" 

To dość kategorycznie przeczy stwierdzeniu, że import string będzie zawsze znajdź wersję std-lib z włączonym importem bezwzględnym. Co więcej, pomimo ostrzeżenia, że import bezwzględny ma stać się zachowaniem „nowym domyślnym”, napotkałem ten sam problem, używając zarówno Pythona 2.7, z dyrektywą __future__, jak i bez niej:

$ python2.7 pkg/main.py Traceback (ostatnie wywołanie ostatnie): Plik "pkg/main.py", wiersz 2, w <module> print string.ascii_uppercase AttributeError: obiekt "module" nie ma atrybutu "ascii_uppercase" $ python2.7 pkg/main2.py Traceback (ostatnie wywołanie ostatnie): Plik "pkg/main2.py", wiersz 3, w <module> print string.ascii_uppercase AttributeError: obiekt "module" nie ma atrybutu "ascii_uppercase" 

jak również Python 3.5, z lub bez (zakładając, że instrukcja print została zmieniona w obu plikach):

$ python3.5 pkg/main.py Traceback (ostatnie wywołanie ostatnie): Plik "pkg/main.py", wiersz 2, w <module> print(string.ascii_uppercase) AttributeError: moduł "string " nie ma atrybutu "ascii_uppercase" $ python3.5 pkg/main2.py Trac eback (ostatnie wywołanie najnowsze): Plik „pkg/main2.py”, wiersz 3, w <module> print(string.ascii_uppercase) AttributeError: moduł "string" nie ma atrybutu "ascii_uppercase" 

Testowałem inne odmiany tego. Zamiast string.py utworzyłem pusty moduł -- katalog o nazwie string zawierający tylko pusty __init__.py -- i zamiast tego wydawania importów z main.py, mam cd"d do pkg i uruchamiam importy bezpośrednio z REPL. Żadna z tych odmian (ani ich połączenie) zmieniło powyższe wyniki. Nie mogę pogodzić tego z tym, co przeczytałem o dyrektywie __future__ i imporcie bezwzględnym.

Wydaje mi się, że można to łatwo wytłumaczyć przez następujący (pochodzi z dokumentacji Pythona 2, ale instrukcja pozostaje niezmieniona w tej samej dokumentacji dla Pythona 3):

sys.path

(...)

Jako zainicjowane podczas uruchamiania programu, pierwsza pozycja na tej liście, path[0], to katalog zawierający skrypt, który został użyty do wywołania interpretera Pythona. y nie jest dostępne (np. jeśli interpreter jest wywoływany interaktywnie lub jeśli skrypt jest odczytywany ze standardowego wejścia), path[0] jest pustym ciągiem, który kieruje Pythona do wyszukiwania modułów w najpierw bieżący katalog.

Czego więc mi brakuje? Dlaczego instrukcja __future__ pozornie nie robi tego, co mówi, i jakie jest rozwiązanie tej sprzeczności między tymi dwoma sekcjami dokumentacji, a także między opisanym a rzeczywistym zachowaniem?

Shop

Learn programming in R: courses

$

Best Python online courses for 2022

$

Best laptop for Fortnite

$

Best laptop for Excel

$

Best laptop for Solidworks

$

Best laptop for Roblox

$

Best computer for crypto mining

$

Best laptop for Sims 4

$

Latest questions

NUMPYNUMPY

psycopg2: insert multiple rows with one query

12 answers

NUMPYNUMPY

How to convert Nonetype to int or string?

12 answers

NUMPYNUMPY

How to specify multiple return types using type-hints

12 answers

NUMPYNUMPY

Javascript Error: IPython is not defined in JupyterLab

12 answers


Wiki

Python OpenCV | cv2.putText () method

numpy.arctan2 () in Python

Python | os.path.realpath () method

Python OpenCV | cv2.circle () method

Python OpenCV cv2.cvtColor () method

Python - Move item to the end of the list

time.perf_counter () function in Python

Check if one list is a subset of another in Python

Python os.path.join () method