Как правильно использовать относительный или абсолютный импорт в модулях Python?
использование относительного импорта в Python имеет один недостаток, вы больше не сможете запускать модули как standalones, потому что вы получите исключение: 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.икс.)
6 ответов
во-первых, я полагаю, вы понимаете, что то, что вы написали, приведет к круговой проблеме импорта, потому что foo imports bar и viceversa; попробуйте добавить
from foo import bar
к test.py и ты увидишь, что это не сработает. Пример должен быть изменен, чтобы работать.
Итак, то, что вы просите, - это действительно вернуться к абсолютному импорту при сбое относительного импорта; на самом деле, если вы выполняете foo.py или bar.py как основной модуль, другие модули будут просто лежать на корневом уровне, и если они поделитесь своим именем с другим модулем в системе, который будет выбран, зависит от заказа в sys.путь. Поскольку текущий dir обычно является первым, локальные модули будут выбраны, если они доступны - то есть, если у вас есть 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
это, вероятно, лучший способ пойти. Это запускает модуль как скрипт.
вы можете просто начать "запускать модули как standalones" немного по-другому:
вместо:
python foo/bar.py
использование:
python -mfoo.bar
конечно,foo/__init__.py
файл должен присутствовать.
обратите внимание, что у вас есть круговая зависимость между foo.py
и bar.py
– это не сработает. Думаю, это просто ошибка в твоем примере.
Update: кажется, он также отлично работает, чтобы использовать это в качестве первой строки foo/bar.py
:
#!/usr/bin/python -mfoo.bar
затем вы можете выполнить скрипт непосредственно в системах POSIX.
Ditch относительный импорт: в любом случае вы должны думать о своем пространстве имен пакета как о глобальном.
трюк, чтобы сделать это приятным является редактирование sys.path
надлежащим образом. Вот пища для размышлений:--3-->
# one directory up _root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) sys.path.insert(0, _root_dir)for now
вам нужно __init__.py
в каждой папке.
относительный импорт работает только тогда, когда вы:
python test.py
test.py импорт foo.py и foo.py может ли относительный импорт чего-либо из папки test.py и выше.
вы не можете сделать:
cd foo
python foo.py
python bar.py
Он не будет работать.
вы можете попробовать sys.путь.добавление или sys.путь.вставьте решение, но вы испортите пути, и у вас будут проблемы с F=open(filename).
до сих пор единственным решением, которое я нашел, было не использовать относительный импорт вообще.
из-за текущего ограничения мне интересно, когда кто-то должен использовать относительный импорт в python.
на всех конфигурациях, которые я использовал sys.path
содержал текущий каталог в качестве первого аргумента, поэтому просто используйте import foo
вместо from . import foo
, потому что он будет делать то же самое.