Абсолютний та явний відносний імпорт модуля Python


85

Мені цікаво про найкращий спосіб імпорту пакетів у програмі 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 років, поки хтось не помітив;)
Даніель Хеппер

Відповіді:


52

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

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

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

import A.A
import A.B.B

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

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


@Rafe, "подивіться на якісь добре написані проекти ..." будь-які пропозиції?
Деніс

@Denis: Rietveld - власний проект Гвідо ван Россума, тому, я думаю, це було б гарним місцем для пошуку ( code.google.com/p/rietveld ). Стандартна бібліотека Python не така чудова, багато цього коду не відповідає умовам.
Рейф Кетлер

68
@Rafe: за словами Гвідо, ця частина PEP-8 застаріла. mail.python.org/pipermail/python-dev/2010- жовтня/104476.html
Брендон Родс

12
Цього твердження зараз уже немає в PEP-8. Зараз зазначено, що рекомендується абсолютний імпорт, але відносний імпорт є прийнятною альтернативою.
dano

6
У мене проблема з абсолютним імпортом полягає у використанні пакету в іншому пакеті. У моєму випадку він присутній як підмодуль git. У цьому випадку, хоча я можу імпортувати пакет верхнього рівня, будь-які пакунки нижче цього не можна імпортувати, оскільки вони не можуть знайти власні модулі з абсолютним імпортом. Тоді як якщо я використовую відносний імпорт на цьому нижчому рівні, все це просто працює.
davidA

122

Відносне імпортування 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.

Це обмеження слід враховувати при оцінці найкращого підходу. У будь-якому випадку Guido проти запуску скриптів з модуля:

Я -1 на цьому та на будь-яких інших запропонованих поворотах машини __main__. Здається, єдиним варіантом використання є запуск сценаріїв, які, здається, живуть всередині каталогу модуля, який я завжди сприймав як антишаблон. Щоб я передумав, вам довелося б переконати мене, що це не так.

Вичерпні дискусії з цього приводу можна знайти на SO; повторно Python 3 це досить вичерпно:


9
Гвідо писав, що в 2010 році, і це все ще в PEP? Як ми можемо довіряти PEP, якщо вони настільки застарілі?
Джабба

2
PEP - це як поправки США в тому сенсі, що ви можете вносити зміни. Є також багато відхилених PEPS. PEP - це пропозиції. Їх можна прийняти, відхилити або застаріти, що часто означає новий ПЕП. PEP 8 - це керівництво стилем, тому його можна змінити на місці.
CppLearner

2
Мене бентежить частина "модуль всередині пакету не може легко імпортувати себе ...". Я ніколи раніше не чув про імпорт модулів.
matiascelasco

2
Один з можливих прикладів @matiascelasco: якщо у вас є foo / bar.py та foo / baz.py, а також baz.py десь ще. Якщо ви хочете імпортувати foo.baz із панелі, ви можете бути впевнені в тому, що імпортуєте, наприклад. import .baz- це лише одне спрощення багатьох подібних ситуацій, описаних у PEP.
Стефано

Ваша відповідь чітко не відрізняє зміну їх дозволу. Неявний відносний імпорт ніколи не повинен використовуватися, але явний відносний імпорт можна використовувати. Неявний родич видалено з Python3.
ninMonkey

33

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


4
Це знеохочений стиль відповідно до керівництва стилем Python. Вони погано читають хмару, і вони не варті уявної "зручності", на яку ви натякаєте. Якщо вам потрібно використовувати відносний імпорт для вирішення проблеми, ви робите це неправильно.
Рейф Кетлер

14
Зверніть увагу на його коментар (Брендон Роудс) щодо іншої відповіді із посиланням, яке показує, що це більше не заважає.
Джон Кумбс,

1
@RafeKettler, чи можете ви пояснити, як ви використовуєте абсолютний імпорт у пакеті, який сам входить до іншого пакету? Абсолютний імпорт зазнає невдачі у внутрішньому пакеті, оскільки вони не знають про новий верхній рівень. Відносний імпорт продовжує працювати. Можна, напевно, стверджувати, що пакет не повинен бути вкладеним всередину іншого, в першу чергу, але якийсь код призначений для багаторазового використання, і це трапляється багато. Багато повторно використаних кодів не упаковуються для загального користування, а тому не надаються як окремий пакет, тому замість них використовуються спеціальні методи, такі як імпорт / підмодулі VCS
davidA

3
@meowsqueak Я згоден, деякі пакети непросто встановлювати (вони не знаходяться в pip, ви не хочете їх використовувати python setup.py installабо python setup.py developз якоїсь причини), у цих випадках я розгалужую вихідний код і додаю його як підмодуль git. Коли ці пакунки використовують абсолютний імпорт на власне ім’я пакета, їх імпорт не вдається. Єдиним рішенням є використання явного відносного імпорту. Це те, що слід заохочувати, я думаю.
CMCDragonkai,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.