python - python:从工作目录中稳健地导入模块
问题描述
为简单起见,我在 python 模块中为我的程序定义参数。然后使用 加载这些参数import
。因此,我必须确保始终从工作目录加载,而不是其他任何地方(独立于执行脚本的位置或 python 路径中的可用模块)。
我找到了两个解决方案。首先修改路径:
import sys
from os import getcwd
import_path = sys.path
sys.path = [str(getcwd(), ]
import xxx
sys.path = import_path
或使用importlib
from pathlib import Path
from importlib.util import module_from_spec, spec_from_file_location
spec = spec_from_file_location('xxx', str(Path('.').expanduser()/'xxx.py'))
xxx = module_from_spec(spec)
spec.loader.exec_module(xxx)
当然,这可以分别包装到上下文管理器或函数中。
pythonic的方法是什么?这两种方法有优点和缺点吗?
我检查了如何导入位于当前工作目录中的 Python 库? 以及将python 包从本地目录导入解释器,但它们缺乏对健壮性的关注。
解决方案
可以通过修改路径来实现本地导入。上下文管理器是一个合适的解决方案:
import sys
from pathlib import Path
from contextlib import contextmanager
@contextmanager
def local_import(dir_=None):
"""Only import modules within `dir_` (default: cwd)."""
if dir_ is None:
dir_ = Path.cwd()
else:
dir_ = Path(dir_).absolute().resolve(strict=True)
import_path0 = sys.path[0]
sys.path[0] = str(dir_)
try:
yield
finally:
sys.path[0] = import_path0
然后可以使用标准导入语法完成本地导入
with local_import():
import xxx
此解决方案依赖于扫描路径的顺序,因此我们暂时替换sys.path[0]
. 我们替换它,而不是预先避免与脚本目录的导入冲突。
笔记
您必须小心避免名称冲突,因为使用了 import 语句,具有相同名称的模块只会被导入一次。因此,如果工作目录和原始目录中存在同名的不同模块,则sys.path[0]
只会导入其中一个。因此,local_import
应该只用于只使用标准库或安装的第三方库的脚本,而不是用于从目录中导入其他脚本的脚本。对于不太可能的情况,您要导入具有相同名称的不同文件,可以使用以下功能:
import uuid
from importlib.util import module_from_spec, spec_from_file_location
def import_file(file, content=None):
"""Try importing `file` as module avoiding name clashes.
If `content` is given `content = import_file('file.py', 'content')`
roughly corresponds to `from file import content`
else `file = import_file('file.py')`
roughly corresponds to `import file`.
Parameters
----------
file : str or Path
The Python file corresponding to the module.
content : str, optional
What to import from the module (optional).
"""
file = Path(file).expanduser().resolve(strict=True)
print(file)
spec = spec_from_file_location(file.stem + str(uuid.uuid4()), str(file))
module = module_from_spec(spec)
spec.loader.exec_module(module)
if content:
print(module)
return getattr(module, content)
else:
return module
推荐阅读
- javascript - 如何检查 props.hisory.goBack 是否有反应价值?
- r - 如何绘制两个变量的密度函数?
- django - TypeError:“QuerySet”和“int”实例之间不支持“>=”
- python - 使用 spark 为 python 代码运行 Teradatasql 驱动程序
- arrays - 从 rust 中的数组转换的字符串中删除额外的长度
- curl - 在同一应用程序上的许多动态加载的 DLL 之一中使用 CURL
- c - 函数指针算法
- spring - 方法级别的@PreAuthorize - 如何将类级别变量注入自定义 PreAuthorize 方法参数
- java - 如何在工具提示文本 JLabel 中使用数据 URI?
- django - 如何通过拖放在 django 中上传图像