Кто-нибудь может объяснить относительный импорт Python?
Я не могу на всю жизнь заставить относительный импорт Python работать. Я создал простой пример, где он не работает:
Структура каталогов:
/__init__.py
/start.py
/parent.py
/sub/__init__.py
/sub/relative.py
/start.py
содержит только: import sub.relative
/sub/relative.py
содержит только from .. import parent
Все остальные файлы пустые.
При выполнении следующего в командной строке:
$ cd /
$ python start.py
Я получил:
Traceback (most recent call last):
File "start.py", line 1, in <module>
import sub.relative
File "/home/cvondrick/sandbox/sub/relative.py", line 1, in <module>
from .. import parent
ValueError: Attempted relative import beyond toplevel package
Я использую Python 2.6. Почему это так? Как мне заставить этот пример с песочницей работать?
2 ответа
Вы импортируете из пакета "sub". start.py
не входит в пакет, даже если есть __init__.py
подарок.
Вам нужно будет запустить вашу программу из одного каталога более parent.py
:
./start.py
./pkg/__init__.py
./pkg/parent.py
./pkg/sub/__init__.py
./pkg/sub/relative.py
С start.py
:
import pkg.sub.relative
Теперь pkg - это пакет верхнего уровня, и ваш относительный импорт должен работать.
Если вы хотите придерживаться вашего текущего макета, вы можете просто использовать import parent
, Потому что вы используете start.py
запустить свой переводчик, каталог, где start.py
находится в вашем пути Python. parent.py
живет там как отдельный модуль.
Вы также можете безопасно удалить верхний уровень __init__.py
, если вы ничего не импортируете в скрипт дальше по дереву каталогов.
Если вы собираетесь позвонить relative.py
напрямую, т.е. если вы действительно хотите импортировать из модуля верхнего уровня, вы должны явно добавить его в sys.path
список.
Вот как это должно работать:
# Add this line to the beginning of relative.py file
import sys
sys.path.append('..')
# Now you can do imports from one directory top cause it is in the sys.path
import parent
# And even like this:
from parent import Parent
Если вы думаете, что вышеизложенное может вызвать некоторую несогласованность, вы можете использовать это вместо:
sys.path.append(sys.path[0] + "/..")
sys.path[0]
относится к пути, с которого была запущена точка входа.
Проверяем это в python3:
python -V
Python 3.6.5
Пример1:
.
├── parent.py
├── start.py
└── sub
└── relative.py
- start.py
import sub.relative
- parent.py
print('Hello from parent.py')
- sub/relative.py
from .. import parent
Если мы запустим его так (просто чтобы убедиться, что PYTHONPATH пуст):
PYTHONPATH='' python3 start.py
Выход:
Traceback (most recent call last):
File "start.py", line 1, in <module>
import sub.relative
File "/python-import-examples/so-example-v1/sub/relative.py", line 1, in <module>
from .. import parent
ValueError: attempted relative import beyond top-level package
Если мы изменим импорт в sub/relative.py
- sub/relative.py
import parent
Если мы запустим его так:
PYTHONPATH='' python3 start.py
Выход:
Hello from parent.py
Пример 2:
.
├── parent.py
└── sub
├── relative.py
└── start.py
- parent.py
print('Hello from parent.py')
- sub/relative.py
print('Hello from relative.py')
- sub/start.py
import relative
from .. import parent
Запустите это так:
PYTHONPATH='' python3 sub/start.py
Выход:
Hello from relative.py
Traceback (most recent call last):
File "sub/start.py", line 2, in <module>
from .. import parent
ValueError: attempted relative import beyond top-level package
Если мы изменим импорт в sub/start.py
:
- sub/start.py
import relative
import parent
Запустите это так:
PYTHONPATH='' python3 sub/start.py
Выход:
Hello from relative.py
Traceback (most recent call last):
File "sub/start.py", line 3, in <module>
import parent
ModuleNotFoundError: No module named 'parent'
Запустите это так:
PYTHONPATH='.' python3 sub/start.py
Выход:
Hello from relative.py
Hello from parent.py
Также лучше использовать импорт из корневой папки, т.е.
- sub/start.py
import sub.relative
import parent
Запустите это так:
PYTHONPATH='.' python3 sub/start.py
Выход:
Hello from relative.py
Hello from parent.py