ValueError: попытка относительного импорта за пределы пакета верхнего уровня
Я играл в систему импорта Python, чтобы лучше понять, как это работает, и я столкнулся с другой проблемой. У меня есть следующая структура
pkg/
__init__.py
c.py
d.py
subpkg/
__init__.py
a.py
b.py
Внутри a.py
У меня есть следующий код:
from . import b
from .. import d
И внутри c.py
у меня есть следующее:
import subpkg.a
Теперь я получаю следующую ошибку:
ValueError: попытка относительного импорта за пределы пакета верхнего уровня
Но почему? Как я могу это решить? Я запускаю c.py
из IDLE, а pkg
следует рассматривать как пакет, так как он имеет файл __init__.py
.
Первый импорт работает отлично, но это не работает:
from .. import d
Потому что я пытаюсь импортировать что-то из родительского пакета, но, по-видимому, я не могу, по какой-то странной причине.
Ответы
Ответ 1
Python 3 изменил систему импорта, поэтому каждый раз, когда вам нужен модуль, который находится рядом с тем, с которым вы работаете, вам необходим относительный импорт (если только вы не sys.path
с PYTHONPATH
или sys.path
).
Правильное использование здесь должно быть
from .subpkg import a
Когда вы работаете с IDLE, у вас совершенно другая среда. Таким образом, вы можете добавить текущее местоположение к вашему пути, чтобы импорт снова работал.
пытаться:
sys.path.insert(0, '')
Это может быть странно, но для большего блага
PS: Если эта последняя вещь не работает - у меня сейчас нет среды IDLE - возможно, потому, что рабочий каталог установлен неправильно.
Попробуйте вместо этого ответ: fooobar.com/questions/261782/...
Ответ 2
Это заставило меня усомниться в моем безумии.
Проблема связана с тем, что люди ошибочно воспринимают относительный импорт как относительный путь, а это не так.
Относительный импорт зависит от местоположения запускаемого файла.
Этот ответ более подробно объясняет, как на самом деле работают модули python, но суммирует.
- Когда файл загружен, ему присваивается имя:
- Если он был загружен как скрипт верхнего уровня (запускается напрямую), его имя -
__main__
.
- Если он был загружен как модуль (с импортом), его именем является имя файла, которому предшествуют имена любых пакетов/подпакетов, частью которых он является, разделенных точками -
pkg.subpkg.a
- Если вы делаете
from ..
, в имени файла должно быть как минимум 2 точки. from ...
- 3 точки.
Теперь самое интересное.
Если вы запускаете c.py напрямую, то ему присваивается имя __main__
, а a.py имеет subpkg.a
.
Согласно второму утверждению, у вас должно быть как минимум 2 точки на имя subpkg.a
для запуска from ..
внутри него.
Исправление
Создайте новый файл вне pkg, скажем, main.py
pkg/
__init__.py
c.py
d.py
subpkg/
__init__.py
a.py
b.py
main.py
Внутри main.py
import pkg.c
Если мы запустим main.py, он получит имя __main__
, а a.py get pkg.subpkg.a
. Согласно второму утверждению, у него теперь есть 2 точки в имени, и мы можем сделать from ..
Еще кое-что. Теперь, когда c.py загружен как модуль, мы должны использовать from для загрузки a.py.
from .subpkg import a
Ответ 3
Я нашел это решение:
#! /usr/bin/env python
import os
import sys
sys.path.append(os.path.realpath('.'))
from d import *