У меня ответил вопрос об абсолютном импорте в Python, который, как я думал, я понял, основываясь на чтении журнал изменений Python 2.5 и сопровождающий PEP. Однако при установке Python 2.5 и попытке создать пример правильного использования from __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
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'
Однако, далее в 2.5 changelog, мы находим это (выделено мной):
В 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
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'
Это довольно категорически противоречит утверждению, что import string будет всегда найти версию std-lib с включенным абсолютным импортом. Что еще, несмотря на предупреждение о том, что абсолютный импорт станет "новым по умолчанию", я столкнулся с этой проблемой, используя как Python 2.7, так и без директивы __future__:
$ 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'
а также Python 3.5 с или без (при условии, что оператор print изменяется в обоих файлах):
$ 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'
Я тестировал другие варианты этого. Вместо string.py я создал пустой модуль - каталог с именем string, содержащий только пустой __init__.py - и вместо выдачи импорта из main.py у меня есть cd 'd to pkg и запускать импорт непосредственно из REPL. Ни один из этих вариантов (а также их комбинация) не изменили результаты выше. Я не могу смириться с тем, что я прочитал о директиве __future__ и абсолютном импорте.
Мне кажется, что это легко объясняется следующим (это из документов Python 2, но это утверждение остается неизменным в том же docs для Python 3):
sys.path
(...)
Как инициализировано при запуске программы, первым элементом этого списка,
path[0], является каталог, содержащий script, который использовался для вызова интерпретатора Python. Если каталог script недоступен (например, если интерпретатор вызывается интерактивно или если script считывается со стандартного ввода),path[0]- это пустая строка , которая направляет Python на поиск модулей в текущей сначала.
Так что мне не хватает? Почему оператор __future__, по-видимому, не делает то, что он говорит, и какова резолюция этого противоречия между этими двумя разделами документации, а также между описанным и фактическим поведением?