, Используйте абсолютный импорт:
Стандартная библиотека четко документируеткак импортировать исходные файлы напрямую (учитывая абсолютный путь к исходному файлу), но этот подход не работает, если в этом исходном файле используется неявный импорт одноуровневого элемента, как описано в примере ниже.
Как этот пример можно адаптировать для работы при наличии неявного родственного импорта?
Я уже проверилэтот а такжеэтот другой Stackoverflow вопросы по теме, но они не относятся к имплицитному импортув файл импортируется вручную.
Установка / ПримерВот иллюстративный пример
Структура каталогов:
root/
- directory/
- app.py
- folder/
- implicit_sibling_import.py
- lib.py
app.py
:
import os
import importlib.util
# construct absolute paths
root = os.path.abspath(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
isi_path = os.path.join(root, 'folder', 'implicit_sibling_import.py')
def path_import(absolute_path):
'''implementation taken from https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly'''
spec = importlib.util.spec_from_file_location(absolute_path, absolute_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
isi = path_import(isi_path)
print(isi.hello_wrapper())
lib.py
:
def hello():
return 'world'
implicit_sibling_import.py
:
import lib # this is the implicit sibling import. grabs root/folder/lib.py
def hello_wrapper():
return "ISI says: " + lib.hello()
#if __name__ == '__main__':
# print(hello_wrapper())
Бегpython folder/implicit_sibling_import.py
сif __name__ == '__main__':
блок закомментировал выходыISI says: world
в Python 3.6.
Но работаетpython directory/app.py
выходы:
Traceback (most recent call last):
File "directory/app.py", line 10, in <module>
spec.loader.exec_module(module)
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
File "/Users/pedro/test/folder/implicit_sibling_import.py", line 1, in <module>
import lib
ModuleNotFoundError: No module named 'lib'
Временное решениеЕсли я добавлюimport sys; sys.path.insert(0, os.path.dirname(isi_path))
вapp.py
, python app.py
доходностьworld
как и предполагалось, но я бы хотел избежатьsys.path
если возможно.
мне бы хотелосьpython app.py
печататьISI says: world
и я хотел бы сделать это, изменивpath_import
функция.
Я не уверен в последствиях искаженияsys.path
, Например. если бы былdirectory/requests.py
и я добавил путь кdirectory
кsys.path
Я бы не хотелаimport requests
начать импортdirectory/requests.py
вместо импортабиблиотека запросов что я установил сpip install requests
.
РешениеДОЛЖЕН быть реализован как функция Python, которая принимает абсолютный путь к файлу к нужному модулю и возвращаетмодульный объект.
В идеале, решение не должно вводить побочные эффекты (например, если оно изменяетsys.path
должно вернутьсяsys.path
в исходное состояние). Если решение вводит побочные эффекты, оно должно объяснить, почему решение не может быть достигнуто без введения побочных эффектов.
PYTHONPATH
Если у меня есть несколько проектов, я не хочу помнить, чтобы установитьPYTHONPATH
каждый раз, когда я переключаюсь между ними. Пользователь должен просто иметь возможностьpip install
мой проект и запустить его без каких-либо дополнительных настроек.
-m
-m
флаг является рекомендуемым / питоническим подходом, но стандартная библиотека также четко документируетКак импортировать исходные файлы напрямую, Я хотел бы знать, как я могу адаптировать этот подход, чтобы справиться с неявным относительным импортом. Ясно, что внутренности Python должны это делать, так чем же они отличаются от документации «импортировать исходные файлы напрямую»?