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

90

Меня интересует предпочтительный способ импорта пакетов в приложение 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
from .. import A
from . import B

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

Дэниел Хеппер
источник
"явные относительные" примеры - это синтаксические ошибки. Относительный импорт должен быть в форме from _ import ..., так что ваши примеры будут from .. import Aиfrom . import B
MestreLion
@MestreLion Хороший улов, вы абсолютно правы! Я обновил свой вопрос с import ..Aна from .. import A. Примечательно, что прошло всего 9 лет, прежде чем кто-то заметил;)
Дэниел Хеппер

Ответы:

56

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

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

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

import A.A
import A.B.B

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

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

Рэйф Кеттлер
источник
@Rafe, "посмотри на несколько хорошо написанных проектов ..." есть предложения?
denis
@Denis: Ритвельд - собственный проект Гвидо ван Россума, так что я думаю, это хорошее место для поиска ( code.google.com/p/rietveld ). Стандартная библиотека Python не так уж хороша, большая часть этого кода не соответствует соглашениям.
Rafe Kettler
68
@Rafe: эта часть PEP-8 устарела, по словам Гвидо. mail.python.org/pipermail/python-dev/2010-October/104476.html
Брэндон Роудс,
13
Этого утверждения больше нет в PEP-8. Теперь он заявляет, что рекомендуется абсолютный импорт, но относительный импорт является приемлемой альтернативой.
dano 01
6
Проблема с абсолютным импортом возникает при использовании пакета в другом пакете. В моем случае он присутствует как подмодуль git. В этом случае, хотя я могу импортировать пакет верхнего уровня, любые пакеты ниже этого не могут быть импортированы, потому что они не могут найти свои собственные модули с абсолютным импортом. Тогда как если я использую относительный импорт на этом нижнем уровне, все просто работает.
davidA 01
125

Относительный импорт 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 был импортирован как модуль - вы не можете выполнить file.py с относительным импортом, иначе вы получите файл ValueError: Attempted relative import in non-package.

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

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

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

Стефано
источник
9
Гвидо написал это в 2010 году, а он все еще находится в PEP? Как мы можем доверять политическим деятелям, если они настолько устарели?
Джабба
2
PEP похожи на поправки США в том смысле, что вы можете вносить поправки. Также есть много отвергнутых PEPS. PEP - это предложения. Они могут быть приняты, отклонены или станут устаревшими, что часто означает появление новых политически значимых лиц. PEP 8 - это руководство по стилю, поэтому его можно изменить на месте.
CppLearner
2
Меня смущает часть «модуль внутри пакета не может легко импортировать себя ...». Я никогда раньше не слышал об импорте модулей.
matiascelasco 03
2
Один из возможных примеров @matiascelasco: если у вас есть foo / bar.py и foo / baz.py, но также есть baz.py где-то еще. Если вы хотите импортировать foo.baz из панели, вы можете быть уверены в том, что вы импортируете, например. import .baz- это всего лишь одна из множества подобных ситуаций, описанных в PEP.
Стефано
В вашем ответе нет четкого различия в разрешении. Неявный относительный импорт никогда не следует использовать, но можно использовать явный относительный импорт. Неявный родственник был удален из Python3.
ninMonkey
33

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

Брэндон Роудс
источник
4
Согласно руководству по стилю Python, это не рекомендуется. Они сильно затуманивают читабельность и не стоят того воспринимаемого «удобства», о котором вы говорите. Если вам нужно использовать относительный импорт для решения проблемы, значит, вы делаете это неправильно.
Rafe Kettler
14
Обратите внимание на его (Брэндон Роудс) комментарий к другому ответу со ссылкой, показывающей, что это больше не обескураживает.
Джон Кумбс
1
@RafeKettler, можете ли вы объяснить, как использовать абсолютный импорт в пакете, который сам включен в другой пакет? Абсолютный импорт во внутреннем пакете завершится ошибкой, потому что он не знает о новом верхнем уровне. Относительный импорт продолжает работать. Вероятно, можно было бы возразить, что пакет не должен быть вложен в другой в первую очередь, но некоторый код предназначен для повторного использования, и это происходит часто. Большая часть повторно используемого кода не упакована для публики и поэтому не предоставляется в виде отдельного пакета, поэтому вместо этого используются специальные методы, такие как импорт / подмодули VCS
davidA
3
@meowsqueak Я согласен, некоторые пакеты нелегко установить (они не в pip, вы не хотите использовать python setup.py installили python setup.py developпо какой- либо другой причине), в этих случаях я создаю исходный код и добавляю его как подмодуль git. Когда эти пакеты используют абсолютный импорт для своего собственного имени пакета, их импорт завершается ошибкой. Единственное решение - использовать явный относительный импорт. Я думаю, это следует поощрять.
CMCDragonkai