Я предполагаю, что когда вы говорите " испытания в grok.py ", вы запускаете его так:
python3 graphics/A/grok.py
python3 A/grok.py
python3 grok.py
Из документации Python по Пакетам и Внутрипакетным ссылкам есть примечание:
Обратите внимание, что относительный импорт основан на названии текущего
модуль. Поскольку имя основного модуля всегда "__main__
",
модули, предназначенные для использования в качестве основного модуля приложения Python
всегда должен использовать абсолютный импорт .
Когда вы запускаете grok.py
, он рассматривается как основной модуль, и импорт будет работать, только если вы использовали абсолютный импорт (при условии, что вы не внесли изменений в sys.path
, мы вернемся к этому позже). Вы можете проверить это, поместив print(__name__)
в начало grok.py, который выведет "__main__
".
Ваш относительный импорт на самом деле будет работать, если у вас был отдельный файл Python (например, main.py
) в графическом пакете, который вызывает ваш модуль grok
:
├── graphics
│ ├── __init__.py
| ├── main.py <<---- add this
│ ├── A
│ ├── B
В main.py
давайте просто импортируем модуль grok
:
from A import grok
В grok.py
давайте проверим относительный импорт:
from . import spam
spam.spam_func()
from .spam import spam_func
spam_func()
from B import bar
bar.bar_func()
В spam.py
:
def spam_func():
print("spammy")
В bar.py
:
def bar_func():
print("barry")
При запуске main.py
:
graphics$ python3 main.py
spammy
spammy
barry
Вы не получите ни одной из предыдущих ошибок. Относительный импорт работает. Обратите внимание, что для импорта из B
я использовал from B
вместо from ..B
. Это потому, что пути импорта с точки зрения main.py
. Вы можете проверить это, добавив это вверху main.py
:
import sys
print(sys.path)
# prints a list, ['/path/to/graphics/',...]
Если вы сделали from ..B
, что означает /path/to/graphics/../
, что, конечно, не имеет модуля B
(следовательно, вы получите ошибку " попытка относительного импорта за пределы пакета верхнего уровня ") )
Теперь предположим, что вы не хотите использовать отдельный main.py
и хотите запустить grok.py
напрямую. Что вы можете сделать, это вручную добавить путь к пакету graphics
в sys.path
. Тогда вы можете сделать from A
и from B
в grok.py
.
import sys
sys.path.append("/full/path/to/graphics/")
from A import spam
spam.spam_func()
from B import bar
bar.bar_func()
Если вы хотите заняться «взломом» sys.path
, я предлагаю прочитать больше на sys.path
и проверить другие связанные посты, в которых обсуждаются способы добавления путей к sys.path
.