Python 3.5+:如何在隐式兄弟引用存在的情况下,根据完整文件路径动态导入模块?
Python 3.5+:如何在隐式兄弟引用存在的情况下,根据完整文件路径动态导入模块?
问题
标准库明确记录了如何直接导入源文件(给定源文件的绝对路径),但是如果该源文件使用了下面示例中描述的隐式同级导入,则该方法无效。
如何适应隐式同级导入的情况下修改示例以使其工作?
我已经查看了这个和这个其他关于此主题的Stackoverflow问题,但它们没有解决被手动导入的文件中的隐式同级导入的问题。
设置/示例
这是一个说明性的示例
目录结构:
root/ - directory/ - app.py - folder/ - implicit_sibling_import.py - lib.py
app.py
:
import os import importlib.util # 构建绝对路径 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 # 这是隐式同级导入,获取root/folder/lib.py def hello_wrapper(): return "ISI says: " + lib.hello() #if __name__ == '__main__': # print(hello_wrapper())
使用注释掉的if __name__ == '__main__':
块运行python folder/implicit_sibling_import.py
会得到Python 3.6中的ISI says: world
。
但是运行python directory/app.py
会得到:
Traceback (most recent call last): File "directory/app.py", line 10, inspec.loader.exec_module(module) File " ", line 678, in exec_module File " ", line 205, in _call_with_frames_removed File "/Users/pedro/test/folder/implicit_sibling_import.py", line 1, in import lib ModuleNotFoundError: No module named 'lib'
解决方法
如果我在app.py
中添加import sys; sys.path.insert(0, os.path.dirname(isi_path))
,则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
安装的requests库。
解决方案必须作为一个python函数实现,该函数接受所需模块的绝对文件路径并返回模块对象。
理想情况下,解决方案不应引入副作用(例如,如果它确实修改了sys.path
,则应将sys.path
返回到其原始状态)。如果解决方案确实引入副作用,它应解释为什么不能在不引入副作用的情况下实现解决方案。
PYTHONPATH
如果我有多个执行此操作的项目,我不想每次切换项目时都要记住设置PYTHONPATH
。用户只需pip install
我的项目并运行它,无需任何额外设置。
-m
-m
标志是推荐的/Pythonic方法,但标准库还清楚地记录了如何直接导入源文件。我想知道如何适应隐式相对导入的这种方法与“直接导入源文件”文档中的方法有何不同?