为简单起见,我在python模块中为程序定义了参数。然后使用df %>% pull(abscissa) %>% class
#[1] "numeric"
加载这些参数。因此,我必须确保始终从工作目录加载,而从其他任何地方加载(独立于执行脚本或python路径中可用模块的位置)。
我找到了两种解决方案。首先修改路径:
import
或使用import sys
from os import getcwd
import_path = sys.path
sys.path = [str(getcwd(), ]
import xxx
sys.path = import_path
importlib
当然可以将其分别包装到上下文管理器或函数中。
pythonic的方式是什么?这两种方法各有利弊吗?
我检查了How can I import a Python library located in the current working directory? 以及Import python package from local directory into interpreter,但它们缺乏对鲁棒性的关注。
答案 0 :(得分:0)
可以通过修改路径来实现本地导入。上下文管理器是一种合适的解决方案:
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