Подтвердить что ты не робот

Абсолютный и явный относительный импорт модуля Python

Мне интересно, как выбрать импорт пакетов в приложении Python. У меня есть такая структура пакетов, как это:

project.app1.models
project.app1.views
project.app2.models

project.app1.views импортирует project.app1.models и project.app2.models. Есть два способа сделать это, которые приходят на ум.

При абсолютном импорте:

import A.A
import A.B.B

или с явным относительным импортом, представленным в Python 2.5 с PEP 328:

# explicit relative
import ..A
import .B

Каков самый питонический способ сделать это?

4b9b3361

Ответ 1

Абсолютный импорт. От PEP 8:

Относительный импорт для внутрипакетных импортных поставок не рекомендуется.       Всегда используйте абсолютный путь пакета для всех импорта.       Даже теперь, когда PEP 328 [7] полностью реализован в Python 2.5,       его стиль явного относительного импорта активно обескуражен;       абсолютный импорт более переносимый и обычно более читаемый.

Явный относительный импорт - хорошая функция языка (я думаю), но они не так явно выражены, как абсолютный импорт. Более читаемая форма:

import A.A
import A.B.B

особенно если вы импортируете несколько разных пространств имен. Если вы посмотрите на некоторые хорошо написанные проекты/учебники, содержащие импорт из пакетов, они обычно следуют этому стилю.

Несколько лишних нажатий клавиш, которые вы принимаете, чтобы быть более явными, могут спасти других (и, возможно, вам) много времени в будущем, когда они попытаются выяснить ваше пространство имен (особенно если вы перейдете на 3.x, в котором некоторые из названий пакетов изменились).

Ответ 2

Относительный импорт Python больше не сильно обескуражен, но в этом случае настоятельно рекомендуется использовать absolute_import.

Пожалуйста, смотрите это обсуждение, ссылаясь на самого Гвидо:

"Разве это не является главным образом историческим? До нового синтаксиса относительного импорта были реализованы различные проблемы с относительным импортом. краткосрочное решение было рекомендовать не использовать их. Долгосрочный решение заключалось в том, чтобы реализовать однозначный синтаксис. Теперь пришло время снять антирекомендацию. Конечно, не выходя за борт - Я все еще нахожу их приобретенным вкусом; но они имеют свое место".

OP правильно связывает PEP 328, в котором говорится:

Было представлено несколько вариантов использования, наиболее важным из которых является способный перестраивать структуру больших пакетов без необходимости редактировать подпакеты. Кроме того, модуль внутри пакета не может легко импортировать себя без относительного импорта.

Также см. почти дублированный вопрос Когда или почему использовать относительный импорт в Python

Конечно, он по-прежнему стоит на вкус. В то время как легче перемещать код с относительным импортом, это может также неожиданно нарушить вещи; и переименование импорта не так уж сложно.

Чтобы заставить новое поведение из PEP 328 использовать:

from __future__ import absolute_import

В этом случае неявный относительный импорт больше невозможен (например, import localfile больше не будет работать, только from . import localfile). Для чистого и будущего поведения, рекомендуется использовать absolute_import.

Важным предостережением является то, что из-за PEP 338 и PEP 366, относительный импорт требует, чтобы файл python был импортирован как модуль - вы не можете выполнить файл .py, который имеет относительный импорт, или вы получите ValueError: Attempted relative import in non-package.

Это ограничение следует учитывать при оценке наилучшего подхода. Guido в любом случае против запуска скриптов из модуля:

Я нахожусь на этом и на любых других предлагаемых твидлингах машины __main__. Единственный случай использования, похоже, заключается в запуске скриптов, которые, случается, живут внутри каталога модулей, которые я всегда рассматривал как антипаттерн. Чтобы заставить меня передумать, вам придется убедить меня, что это не так.

Подробные обсуждения по этому вопросу можно найти на SO; число рейнольдса Python 3 это довольно полно:

Ответ 3

Относительный импорт не только позволяет вам свободно переименовывать ваш пакет позже, не изменяя десятки внутренних импортных товаров, но я также имел успех с ними в решении определенных проблем, связанных с такими вещами, как циклический импорт или пакеты пространства имен, поскольку они не отправляют Python "вернуться к началу", чтобы снова начать поиск следующего модуля из пространства имен верхнего уровня.