2010-09-01 3 views
26

Использование относительных импорта в Python имеет один недостаток, вы не будете иметь возможность запускать модули как standalones больше, потому что вы получите исключение: ValueError: Attempted relative import in non-packageКак правильно использовать относительный или абсолютный импорт в модулях Python?

# /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

Отметьте эту тему: http://www.velocityreviews.com/forums/t502905-relative-import-broken.html –

+0

Спасибо, к сожалению, я знал об этом старом потоке, но я не нашел решения проблемы. До сих пор я наблюдал только много людей, жалующихся на это. Нам нужно четкое решение/пример для этой проблемы. – sorin

+0

Связанный: [Как узнать, был ли запущен скрипт python с помощью опции -m интерпретатора?] (Http://stackoverflow.com/questions/8348726/) –

ответ

16

Во-первых, я предполагаю, что вы понимаете, что то, что вы написали, приведет к циклической проблеме импорта, поскольку foo импортирует бар и наоборот; попробуйте добавить

from foo import bar 

для test.py, и вы увидите, что он не работает. Этот пример необходимо изменить для работы.

Итак, что вы просите - это действительно возврат к абсолютному импорту, когда относительный импорт не удается; на самом деле, если вы выполняете foo.py или bar.py в качестве основного модуля, другие модули будут лежать на корневом уровне, и если они разделяют имя с другим модулем в системе, который будет выбран, зависит от порядок в sys.path. Поскольку текущий каталог обычно является первым, локальные модули будут выбраны, если они доступны, т. Е. Если у вас есть файл «os.py» в текущем рабочем каталоге, он будет выбран вместо встроенного.

possibile предложение:

Foo.ру

try: 
    from . import bar 
except ValueError: 
    import bar 

if __name__ == "__main__": 
    pass 

bar.py:

if __name__ == "__main__": 
    pass 

Кстати, призывающей скрипты из правильного положения, как правило, путь лучше.

python -m foo.bar 

Возможно, это лучший способ пойти. Это runs the module as a script.

+0

Я не думаю, что 'import bar' в выражении' except' будет работать для Python 3.1+ – John

+0

@John, насколько я могу судить, нет причин, потому что импорт в исключение не должен работать. Он работает 100% в Python 3.2. –

-2

До сих пор единственным решением, которое я нашел, было вовсе не использование относительного импорта.

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

Во всех конфигурациях, которые я использовал, sys.path содержал текущий каталог в качестве первого аргумента, поэтому используйте import foo вместо from . import foo, потому что он будет делать то же самое.

+3

Но это вызовет проблемы, когда вы решите, что хотите использовать стандарт python или сторонний модуль с тем же именем, что и модуль в вашем пакете. Вот почему IMHO гораздо лучше использовать 'from __future__ import absolute_import' и относительный импорт. –

22

Вы можете просто запустить 'чтобы запустить модули как standalones' в немного другой способ:

Вместо:

python foo/bar.py 

Использование:

python -mfoo.bar 

Конечно, foo/__init__.py файл должен присутствовать.

Обратите внимание, что у вас есть круговая зависимость между foo.py и bar.py - это не сработает. Я думаю, это просто ошибка в вашем примере.

Обновление: кажется, он также работает прекрасно, чтобы использовать это в качестве первой линии foo/bar.py:

#!/usr/bin/python -mfoo.bar 

После этого вы можете выполнить скрипт непосредственно в системах POSIX.

+3

Это уродливый хак, который я считаю неприемлемым, особенно потому, что он намного сложнее их выполнять (особенно в Windows) – sorin

+0

Кстати, пример bogdan работал даже с циклическим импортом. – sorin

+15

+1, это как раз правильный способ «выполнить автономный» модуль ** как часть пакета ** (который вы должны, если хотите использовать относительный импорт, конечно). –

0

Почему бы просто не поместить «главное» в другой .py-файл?

1

Ditch относительный импорт: в любом случае вы должны думать о своем пространстве имен пакетов как глобальном.

Удовлетворение этой привлекательности редактируется 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

-1. Не допускать относительного импорта; они считались прекрасными, когда функция абсолютного импорта была разработана http://mail.python.org/pipermail/python-dev/2003-December/041065.html, и сегодня они прекрасны. – bignose

1

В каждой папке необходимо __init__.py.

Относительный импорт работает только тогда, когда вы делаете:

python test.py 

импорта test.py foo.py и foo.py может родственница импортировать что-либо из папки test.py и выше.

Вы не можете сделать:

cd foo 
python foo.py 
python bar.py 

Это никогда не будет работать.

Вы можете попробовать sys.path.append или sys.path.insert решение, но вы собираетесь испортить пути, и у вас будут проблемы с f = open (имя файла).