Как выполнить относительный импорт в Python
stuff/
__init__.py
mylib.py
Foo/
__init__.py
main.py
foo/
__init__.py
script.py
script.py
хочет импортировать mylib.py
Это всего лишь пример, но на самом деле я просто хочу сделать относительный импорт модуля в родительском каталоге. Я пробовал разные вещи и получаю эту ошибку...
Attempted relative import beyond toplevel package
Я где-то читал, что сценарий, с которого запускается программа, не должен находиться в пакете, и я попытался изменить структуру для этого, например, так...
stuff/
mylib.py
foo.py // equivalent of main.py in above
foo/
__init__.py
script.py
но получил ту же ошибку.
Как я могу сделать это? Это даже адекватный подход?
Изменить: в Python 2
6 ответов
Немного поигравшись с этим, я понял, как его настроить, и ради определенности не буду использовать названия foo bar. Мой каталог проекта настроен как...
tools/
core/
object_editor/
# files that need to use ntlib.py
editor.py # see example at bottom
__init__.py
state_editor/
# files that need to use ntlib.py
__init__.py
ntlib.py
__init__.py # core is the top level package
LICENSE
state_editor.py # equivalent to main.py for the state editor
object_editor.py # equivalent to main.py for the object editor
Линия в object_editor.py
похоже...
from core.object_editor import editor
Линия в editor.py
похоже...
from .. import ntlib
или в качестве альтернативы
from core import ntlib
Ключевым моментом является то, что в примере, который я привел в вопросе, "основной" скрипт запускался из пакета. Как только я переместил его, создал конкретный пакет (core
) и переместил библиотеку, которой хотели поделиться редакторы (ntlib
В эту посылку все было в порядке.
Хотя до тех пор, пока "вещи" не находятся в вашем пути к Python, у вас нет выбора, кроме как добавить путь.
Если вы знаете уровень вашего script.py из вещей, которые вы можете сделать, например:
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
Я использую Python 3.4.2 на Windows 7 и оторвал себе голову.
При запуске любого из них:
python -m unittest обнаружение python -m unittest
... Я бы получил сообщение об ошибке "Попытка относительного импорта за пределы пакета верхнего уровня".
Для меня решением было опустить ".." в моем [test_stock.py]. Линия была: от.. сток импортный склад
Поменял его на: со склада импорт со склада
.. и это работает.
Структура папки:
C:\
|
+-- stock_alerter
|
+-- __init__.py
+-- stock.py
|
\-- tests
|
+-- __init__.py
\-- test_stock.py
import ..foo..stuff.mylib
должно быть хорошо
EDIT снял расширение
Из PEP видно, что вы не можете использовать относительный импорт для импорта файла, который не был упакован.
Так что вам нужно будет добавить __init__.py
набить и изменить свой импорт на что-то вроде from .mylib import *
Тем не менее, PEP, похоже, не учитывает упаковку mylib в модуле. Поэтому вам может потребоваться изменить способ вызова функций библиотеки.
Другая альтернатива - переместить mylib в подпакет и импортировать его как from .libpackage import mylib
Если вы работаете в Linux или, возможно, похожий *nix, вы можете взломать это с помощью символических ссылок.
stuff/
mylib.py
foo.py // equivalent of main.py in above
foo/
script.py
mylib.py -> ../mylib.py
foo2/
script2.py
mylib.py -> ../mylib.py
Это, вероятно, не очень хорошая модель для подражания.
В моем случае я выбрал это, потому что у меня было несколько исполняемых файлов, зависящих от одной и той же библиотеки, которые нужно было поместить в отдельные каталоги.
Реализация новых исполняемых тестов не должна требовать от автора тестов глубокого понимания импорта python.
tests/
common/
commonlib.py
test1/
executable1.py
executable2.py
commonlib.py -> ../common/commonlib.py
test2/
executable1.py
executable2.py
commonlib.py -> ../common/commonlib.py