【发布时间】:2017-06-11 05:08:06
【问题描述】:
问题
标准库清楚地记录了how to import source files directly(给定源文件的绝对文件路径),但如果源文件使用下面示例中描述的隐式同级导入,则此方法不起作用。
如果存在隐式同级导入,该示例如何适应工作?
我已经查看了 this 和 this other 关于该主题的 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())
在 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, 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 安装的requests library。
解决方案必须实现为接受所需模块的绝对文件路径并返回module object的python函数。
理想情况下,解决方案不应引入副作用(例如,如果它确实修改了sys.path,它应该将sys.path 返回到其原始状态)。如果解决方案确实引入了副作用,它应该解释为什么不引入副作用就无法实现解决方案。
PYTHONPATH
如果我有多个项目这样做,我不想每次在它们之间切换时都要记住设置PYTHONPATH。用户应该能够pip install 我的项目并运行它而无需任何额外设置。
-m
-m flag 是推荐的/pythonic 方法,但标准库也清楚地记录了How to import source files directly。我想知道如何调整这种方法来应对隐式相对导入。显然,Python 的内部必须这样做,那么内部和“直接导入源文件”文档有何不同?
【问题讨论】:
-
就 Python 而言,这种“隐式同级导入”是普通的绝对导入,绝对不是隐式相对导入。 Python 3 不再支持隐式相对导入。
-
更改
sys.path可能是您最好的选择。无论你做什么来让导入机制在该文件的文件夹中查找,它都必须在初始导入的持续时间之后徘徊,因为当你调用它们时,来自该文件的函数可能会执行进一步的导入。 -
@user2357112 确实,PEP 8 确实说在 Python 3 中禁用了相对隐式导入。但我想知道:如果上面的示例不是相对隐式导入,那是什么?你有例子吗?
-
@user2357112
import lib行没有指定任何包名,也没有使用.。那么,唯一不会使隐式相对导入不是在包中完成的事实吗? -
@DarrickHerwehe 正如问题中所述,修改
sys.path是可以的,只要你能证明它是合理的。在这种情况下,只需要“解释为什么修改sys.path是最佳选择”。
标签: python python-3.x import python-importlib