python:从工作目录中可靠地导入模块

时间:2019-02-15 10:36:48

标签: python python-3.x

为简单起见,我在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,但它们缺乏对鲁棒性的关注。

1 个答案:

答案 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