Я ответил на вопрос об абсолютном импорте в 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 мы находим это (выделение добавлено):
В 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
будет всегда найти версию станд-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
был pkg
выполнять импорт непосредственно из REPL. Ни один из этих вариантов (ни их комбинация) не изменил результаты выше. Я не могу совместить это с тем, что я прочитал о __future__
директиве и абсолютном импорте.
Мне кажется, что это легко объяснить следующим (это из документов Python 2, но это утверждение остается неизменным в тех же документах для Python 3):
sys.path
(...)
Как инициализируется при запуске программы, первым элементом этого списка
path[0]
является каталог, содержащий скрипт, который использовался для вызова интерпретатора Python. Если каталог скриптов недоступен (например, если интерпретатор вызывается в интерактивном режиме или если скрипт читается из стандартного ввода),path[0]
это пустая строка, которая направляет Python для поиска модулей в текущем каталоге в первую очередь.
Так чего мне не хватает? Почему __future__
утверждение, по-видимому, не соответствует тому, что оно говорит, и каково разрешение этого противоречия между этими двумя разделами документации, а также между описанным и фактическим поведением?