Вопрос-Ответ

How can I do relative imports in Python?

Как я могу выполнить относительный импорт в Python?

Представьте себе эту структуру каталогов:

app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py

Я занимаюсь программированием mod1, и мне нужно что-то импортировать из mod2. Как я должен это сделать?

Я пытался from ..sub2 import mod2, но получаю сообщение "Попытка относительного импорта без пакета".

Я погуглил, но нашел только хаки "sys.path манипулирования". Нет ли чистого способа?


Все мои __init__.py в данный момент пусты

Я пытаюсь это сделать, потому что sub2 содержит классы, которые являются общими для всех подпакетов (sub1, subX и т.д.).

Поведение, которое я ищу, такое же, как описано в PEP 366 (спасибо Джону Б.).

Переведено автоматически
Ответ 1

Проблема в том, что вы запускаете модуль как '__main__', передавая mod1.py в качестве аргумента интерпретатору.

Из PEP 328:


Относительный импорт использует атрибут __name__ модуля для определения положения этого модуля в иерархии пакетов. Если имя модуля не содержит никакой информации о пакете (например, оно имеет значение '__main__'), то относительный импорт разрешается так, как если бы модуль был модулем верхнего уровня, независимо от того, где модуль фактически расположен в файловой системе.


В Python 2.6 добавлена возможность ссылаться на модули относительно основного модуля. PEP 366 описывает изменение.

Ответ 2

Вот решение, которое работает для меня:

Я выполняю относительный импорт как from ..sub2 import mod2 а затем, если я хочу запустить mod1.py тогда я иду в родительский каталог app и запускаю модуль, используя переключатель python -m как python -m app.sub1.mod1.

Реальная причина, по которой эта проблема возникает при относительном импорте, заключается в том, что относительный импорт работает, используя __name__ свойство модуля. Если модуль запускается напрямую, то __name__ имеет значение __main__ и не содержит никакой информации о структуре пакета. И вот почему python жалуется на relative import in non-package ошибку.

Итак, используя переключатель -m, вы предоставляете python информацию о структуре пакета, с помощью которой он может успешно разрешить относительный импорт.

Я много раз сталкивался с этой проблемой при выполнении относительного импорта. И, прочитав все предыдущие ответы, я все еще не смог понять, как решить это простым способом, без необходимости помещать шаблонный код во все файлы. (Хотя некоторые комментарии были действительно полезны, спасибо @ncoghlan и @XiongChiamiov)

Надеюсь, это поможет кому-то, кто борется с проблемой относительного импорта, потому что проходить PEP на самом деле не весело.

Ответ 3
main.py
setup.py
app/ ->
__init__.py
package_a/ ->
__init__.py
module_a.py
package_b/ ->
__init__.py
module_b.py

  1. Вы запускаете python main.py.

  2. main.py выполняет: import app.package_a.module_a

  3. module_a.py выполняет import app.package_b.module_b

В качестве альтернативы 2 или 3 могли бы использовать: from app.package_a import module_a

Это будет работать до тех пор, пока у вас есть app в вашем PYTHONPATH. main.py тогда это может быть где угодно.

Итак, вы пишете setup.py для копирования (установки) всего пакета приложения и подпакетов в папки python целевой системы и main.py в папки скриптов целевой системы.

Ответ 4

"Guido рассматривает запущенные скрипты внутри пакета как антишаблон" (отклонено PEP-3122)

Я потратил так много времени, пытаясь найти решение, читая связанные сообщения здесь, о Stack Overflow, и говоря себе: "Должен быть способ получше!". Похоже, его нет.

python