Що не так у відносному імпорті в Python?


89

Нещодавно я оновив версії pylint , популярної Python-стилі для перевірки.

Він пройшов балістично в усьому моєму коді, вказуючи місця, де я імпортую модулі в одному пакеті, не вказуючи повний шлях пакета.

Нове повідомлення про помилку - W0403.

W0403: Відносний імпорт% r, повинен бути% r

Використовується при виявленні імпорту відносно каталогу пакунків.


Приклад

Наприклад, якщо мої пакунки структуровані так:

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

а в упаковці губки пишу:

import icing

замість

import cake.icing

Я отримаю цю помилку.


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

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

Відповіді:


97

Проблема 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
@Jack насправді я не думаю, що ти можеш. З цієї частини PEP328 : Відносний імпорт повинен використовуватись завжди from <> import; import <>завжди абсолютний. Звичайно, абсолютний імпорт можна використовувати from <> import, опустивши провідні крапки. Причина import .fooзаборонена, оскільки після import XXX.YYY.ZZZцього XXX.YYY.ZZZвона може бути використана в виразі. Але .moduleYне є корисним у виразі.
A.Wan

48

Є кілька вагомих причин:

  1. Відносний імпорт легко порушується, коли ви переміщуєте модуль.

    Уявіть foo.bar, що у вашому пакеті foo.bazє bazмодуль a , a і . foo.barімпорту foo.baz, але з використанням відносного імпорту.

    Тепер, якщо ви переїхали foo.barдо bar, ваш модуль раптом імпортує інше baz!

  2. Відносний імпорт неоднозначний. Навіть не пересуваючись barмодулем у наведеному вище прикладі, новому розробнику, який приходить до вашого проекту, можна буде пробачити за те, що він не зрозумів, що bazце насправді foo.bazзамість пакету кореневого рівня baz.

    Абсолютний імпорт чітко пояснює, який модуль використовується. І як import thisпроповіді, явне краще, ніж неявне.

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

    Перенесення прикладу з Python 2 на 3 таким чином призведе до несподіваних проблем, використання абсолютного імпорту тепер зробить ваш код надійним у майбутньому.


10
+1 для №2 та №3. Але №1 має бути компенсовано тим, що відбувається при переміщенні всього каталогу (наприклад, натиснуто на рівень).
Відмінна думка
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.