Как правильно использовать относительный или абсолютный импорт в модулях Python?
Использование относительного импорта в Python имеет один недостаток, вы больше не сможете запускать модули как автономные, потому что вы получите исключение: ValueError: Attempted relative import in non-package
# /test.py: just a sample file importing foo module
import foo
...
# /foo/foo.py:
from . import bar
...
if __name__ == "__main__":
pass
# /foo/bar.py: a submodule of foo, used by foo.py
from . import foo
...
if __name__ == "__main__":
pass
Как мне изменить код примера, чтобы иметь возможность выполнить все: test.py
, foo.py
и bar.py
Я ищу решение, которое работает с python 2.6+ (включая 3.x).
Ответы
Ответ 1
Во-первых, я предполагаю, что вы понимаете, что вы написали, что приведет к циклической проблеме импорта, потому что foo import bar и viceversa; попробуйте добавить
from foo import bar
для test.py, и вы увидите, что он не работает. Этот пример должен быть изменен для работы.
Итак, то, что вы просите, действительно относится к абсолютному импорту, когда относительный импорт не удается; на самом деле, если вы выполняете foo.py или bar.py в качестве основного модуля, другие модули будут лежать на корневом уровне, и если они разделяют имя с другим модулем в системе, который будет выбран, зависит от порядок в sys.path. Поскольку текущий каталог обычно является первым, локальные модули будут выбраны, если они доступны, т.е. Если у вас есть файл "os.py" в текущем рабочем каталоге, он будет выбран вместо встроенного.
Возможное предложение:
foo.py
try:
from . import bar
except ValueError:
import bar
if __name__ == "__main__":
pass
bar.py:
if __name__ == "__main__":
pass
Кстати, вызов скриптов из правильной позиции обычно лучше.
python -m foo.bar
Вероятно, это лучший способ. Этот запускает модуль как script.
Ответ 2
Вы можете просто начать "запускать модули как автономные" по-другому:
Вместо:
python foo/bar.py
Использование:
python -mfoo.bar
Конечно, файл foo/__init__.py
должен присутствовать.
Также обратите внимание, что у вас есть круговая зависимость между foo.py
и bar.py
- это не сработает. Я думаю, это просто ошибка в вашем примере.
Обновление: кажется, что он также отлично работает, чтобы использовать его в качестве первой строки foo/bar.py
:
#!/usr/bin/python -mfoo.bar
Затем вы можете выполнить script непосредственно в системах POSIX.
Ответ 3
Относительный импорт канавок: в любом случае вы должны думать о пространстве имен пакетов как глобальном.
Трюк, чтобы сделать это приемлемым, редактирует sys.path
соответствующим образом. Вот пища для размышлений:
# one directory up
_root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.insert(0, _root_dir)for now
Ответ 4
Вам нужно __init__.py
в каждой папке.
Относительный импорт работает только тогда, когда вы делаете:
python test.py
test.py import foo.py и foo.py могут относить импортные данные из папки test.py и выше.
Вы не можете:
cd foo
python foo.py
python bar.py
Он никогда не будет работать.
Вы можете попробовать решение sys.path.append или sys.path.insert, но вы собираетесь испортить пути, и у вас будут проблемы с f = open (имя файла).
Ответ 5
Почему бы просто не поместить "main" в другой .py файл?
Ответ 6
До сих пор единственным решением, которое я нашел, было вовсе не использование относительного импорта.
Из-за текущего ограничения, мне интересно, когда кто-то должен использовать относительный импорт в python.
Во всех конфигурациях, в которых я использовал sys.path
, содержался текущий каталог в качестве первого аргумента, поэтому просто используйте import foo
вместо from . import foo
, потому что он сделает то же самое.