Что не так с относительным импортом в Python?


89

Я недавно обновил версии pylint , популярного средства проверки стиля Python.

Во всем моем коде он стал баллистическим, указывая на места, куда я импортирую модули в одном пакете, без указания полного пути к пакету.

Новое сообщение об ошибке W0403.

W0403: Относительный импорт% r, должен быть% r

Используется при обнаружении импорта относительно каталога пакета.


пример

Например, если мои пакеты структурированы так:

/cake
  /__init__.py
  /icing.py
  /sponge.py
/drink

и в упаковке губки я пишу:

import icing

вместо

import cake.icing

Я получу эту ошибку.


Хотя я понимаю, что не все сообщения Pylint имеют одинаковую важность, и я не боюсь отклонить их, я не понимаю, почему такая практика считается плохой идеей.

Я надеялся, что кто-нибудь сможет объяснить подводные камни, поэтому я мог бы улучшить свой стиль кодирования, а не (как я планирую сделать в настоящее время) отключить это явно ложное предупреждение.

Ответы:


98

Проблема в import icingтом, что вы не знаете, является ли это абсолютным или относительным импортом. icingможет быть модуль в пути Python или пакет в текущем модуле. Это довольно раздражает, когда локальный пакет имеет то же имя, что и стандартный пакет библиотеки Python.

Вы можете сделать, from __future__ import absolute_importчто отключает неявный относительный импорт в целом. Это описано, в том числе с этим обоснованием двусмысленности, в PEP 328 . Я считаю, что в Python 3000 полностью отключен неявный относительный импорт.

Вы все еще можете выполнять относительный импорт, но вы должны делать это явно, например так:

from . import icing

2
+1 особенно за компромиссное решение, которое, вероятно, и должно быть.
Нечетное

2
Обратите внимание, что вы также можете сделать import .icingвместоfrom . import icing
Джек

11
@ Джек, на самом деле я не думаю, что ты можешь. Из этой части PEP328 : всегда следует использовать относительный импорт from <> import; import <>всегда абсолют. Конечно, абсолютный импорт можно использовать from <> import, опуская ведущие точки. Причина import .fooзапрещена, потому что после import XXX.YYY.ZZZэтого XXX.YYY.ZZZможно использовать в выражении. Но .moduleYне может быть использовано в выражении.
A.Wan

47

Есть несколько веских причин:

  1. Относительный импорт легко ломается, когда вы перемещаете модуль.

    Представьте, что у вас есть foo.bar, a foo.bazи bazмодуль в вашей упаковке. foo.barимпорт foo.baz, но с использованием относительного импорта.

    Теперь, если вам нужно перейти foo.barк bar, ваш модуль неожиданно импортирует другой baz!

  2. Относительный импорт неоднозначен. Даже не перемещаясь по barмодулю в вышеприведенном примере, новый разработчик, пришедший в ваш проект, может быть прощен за то, что не осознает, что bazэто на самом деле foo.bazвместо пакета корневого уровня baz.

    Абсолютный импорт делает явным то, какой модуль используется. И, как import thisпроповедует, явное лучше, чем неявное.

  3. Python 3 полностью отключил неявный относительный импорт; import bazimport теперь всегда интерпретируется как абсолютный, что означает, что в приведенном выше примере всегда будет импортироваться модуль верхнего уровня. Вместо этого вам придется использовать явный синтаксис импорта ( from . import baz).

    Таким образом, перенос примера с Python 2 на 3 приведет к неожиданным проблемам, а использование абсолютного импорта сделает ваш код перспективным.


11
+1 за № 2 и № 3. Но # 1 должен быть смещен относительно того, что происходит, когда весь каталог перемещается (например, перемещается вниз на уровень).
Нечетное
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.