TGTGInsighttelegram intelligenceLIVE / telegram public index
← Python Заметки
Python Заметки avatar

TGINSIGHT POST

Post #202

@pythonotes

Python Заметки

Прегледи3,090Број на прегледи
Објавено15 јан.15.01.2021 г., 09:00
Содржина

Содржина на објавата

Релятивный импорт в исполняемом файле Часто встречается ситуация, когда исполняемый скрипт находится внутри Python-пакета. Например, представим такую структуру библиотеки: my_lib/ cmd/ start.py stop.py core.py services.py Для запуска каких-то процессов мне надо исполнить скрипт start.py и вот как я делаю его вызов: python3 /mnt/libs/my_lib/cmd/start.py Пока выглядит всё красиво. Но что, если я внутри этого файла хочу импортировать модуль services.py? При этом я хочу использовать релятивный импорт # start.py if __name__ == "__main__": from .. import services Я получу такую ошибку: ValueError: attempted relative import beyond top-level package Эта ошибка возникает потому, что интерпретатор просто не знает что мы находимся внутри пакета и не может понять куда это мы собрались выйти на уровень выше) Есть три способа как избежать этой ошибки. Все они требуют чтобы библиотека my_lib находилась в доступном для импорта месте, то есть в моëм случае чтобы путь /mnt/libs был в sys.path. 🔸Просто пишем полный путь импорта if __name__ == "__main__": from my_lib import services Это сработает. Но, очевидно, что это не то, что мы ищем. Нам нужен релятивный импорт. 🔸 Если интерпретатору подсказать имя пакета в котором мы находимся, то всё заведётся. И есть два способа это сделать. Первый способ — это запускать не через имя файла а по имени модуля python -m my_lib.cmd.start Уже самой командой мы обозначили все необходимые неймспейсы. 🔸 Если предыдущий способ недоступен (то есть запускаем именно по пути к файлу .../start.py), то объявляем имя пакета прямо внутри кода. Для этого используем переменную модуля __package__ if __name__ == "__main__": if __package__ is None: __package__ = 'my_lib.cmd' from .. import services Кстати, мы также можем при необходимости: 🔹 динамически определить имя пакета в котором находимся 🔹 добавить необходимые пути к основной библиотеке в sys.path перед импортом 🔹 переместить обновление __package__ в начале скрипта вместе со всеми импортами но обязательно с проверкой is None! #tricks