问题
标准库清楚地记录了如何直接导入源文件(给定源文件的绝对文件路径),但如果该源文件使用隐式同级导入,如下例所述,则此方法不起作用。
在存在隐式同级导入的情况下,该示例如何适应工作?
我已经检查了这个和这个关于该主题的其他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 3.6 中运行注释掉python folder/implicit_sibling_import.py
的块会产生收益。if __name__ == '__main__':
ISI says: world
但是运行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
函数来完成这个。
我不确定 mangling 的含义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
标志是推荐的/pythonic 方法,但标准库也清楚地记录了如何直接导入源文件。我想知道如何调整这种方法来应对隐式相对导入。显然,Python 的内部必须这样做,那么内部与“直接导入源文件”文档有何不同?