Я ответил на вопрос об абсолютном импорте в Python, который, как мне казалось, я понял, прочитав журнал изменений Python 2.5 и сопровождающий PEP. Однако после установки Python 2.5 и попытки создать пример правильного использования из __future__ import absolute_import
я понял, что все не так ясно.
Прямо из журнала изменений, указанного выше, это заявление точно резюмировало мое понимание абсолютного изменения импорта:
Допустим, у вас есть каталог пакетов, подобный этому:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
Определяет пакет с именем
pkg
, содержащийpkg.main
иподмодулей pkg.string
.Рассмотрите код в модуле main.py. Что произойдет, если он выполнит оператор
import string
? В Python 2.4 и более ранних версиях он сначала просматривает каталог пакета для выполнения относительного импорта, находит pkg/string.py, импортирует содержимое этого файла как модульpkg.string
, и этот модуль привязан к имени"string"
в именах модулейpkg.main
темп.
Итак, я создал такую точную структуру каталогов:
$ ls -R .:pkg/ ./pkg: __init__.py main.py string .py
__init__.py
и string.py
пусты. main.py
содержит следующий код:
import string print string.ascii_uppercase
Как и ожидалось, запуск с Python 2.5 завершается с ошибкой AttributeError
:
$ python2.5 pkg/main.py Трассировка (самый последний вызов последний): Файл "pkg/main.py", строка 2 , в <модуле> print string.ascii_uppercase AttributeError: объект "module" не имеет атрибута "ascii_uppercase"
Однако далее в журнале изменений 2.5 мы находим это (курсив добавлен):
В Python 2.5 вы можете переключить поведение
import
на абсолютный импорт с помощью директивыfrom __future__ import absolute_import
. Это поведение абсолютного импорта станет поведением по умолчанию в будущая версия (вероятно, Python 2.7). После того, как абсолютный импорт станет значением по умолчанию,import string
всегда будет находить версию стандартной библиотеки.
Таким образом, я создал pkg/main2.py
, идентичный main.py
, но с дополнительной директивой импорта будущего. Теперь это выглядит так:
from __future__ import absolute_import import string print string.ascii_uppercase
Однако выполнение этого с Python 2.5... AttributeError
:
$ python2.5 pkg/main2.py Трассировка (последний последний вызов): файл "pkg/main2.py", строка 3, < ;модуль> print string.ascii_uppercase AttributeError: объект "module" не имеет атрибута "ascii_uppercase"
Это категорически противоречит утверждению, что import string
будет всегда найдите версию std-lib с включенным абсолютным импортом. Более того, несмотря на предупреждение о том, что абсолютный импорт должен стать «новым поведением по умолчанию», я столкнулся с той же проблемой, используя оба Python 2.7, с директивой __future__
или без нее:
$ python2.7 pkg/main.py Трассировка (последний последний вызов): Файл "pkg/main.py", строка 2, в <module> print string.ascii_uppercase AttributeError: объект "module" не имеет атрибута "ascii_uppercase" $ python2.7 pkg/main2.py Трассировка (последний последний вызов): Файл "pkg/main2.py", строка 3, в <module> print string.ascii_uppercase AttributeError: объект "module" не имеет атрибута "ascii_uppercase"
а также Python 3.5, с или без (при условии, что оператор print
изменен в обоих файлах):
$ python3.5 pkg/main.py Трассировка (последний последний вызов): Файл "pkg/main.py", строка 2, в <module> print(string.ascii_uppercase) AttributeError: module "string " не имеет атрибута "ascii_uppercase" $ python3.5 pkg/main2.py Trac eback (последний последний вызов): файл "pkg/main2.py", строка 3, в <module> print(string.ascii_uppercase) AttributeError: модуль "string" не имеет атрибута "ascii_uppercase"
Я тестировал другие варианты этого. Вместо string.py
я создал пустой модуль — каталог с именем string
, содержащий только пустой __init__.py
— и вместо этого импорта из main.py
, я использую cd
"d в pkg
и запускаю импорт непосредственно из REPL. Ни один из этих вариантов (ни их комбинация) изменила приведенные выше результаты. Я не могу согласовать это с тем, что я читал о директиве __future__
и абсолютном импорте.
Мне кажется, что это легко объяснимо с помощью следующего (это из документации Python 2, но это оператор остается неизменным в тех же документах для Python 3):
sys.path
(...)
Как инициализируется при запуске программы, первый элемент этого списка,
path[0]
, — это каталог, содержащий сценарий, который использовался для вызова интерпретатора Python. y недоступен (например, если интерпретатор вызывается интерактивно или если сценарий читается из стандартного ввода),path[0]
— это пустая строка, указывающая Python на поиск модулей в сначала текущий каталог.
Итак, что я упускаю? Почему оператор __future__
вроде бы не делает того, о чем говорит, и как разрешается это противоречие между этими двумя разделами документации, а также между описанным и реальным поведением?