如何加载给定完整路径的Python模块?

请注意,文件可以位于文件系统中用户具有访问权限的任何位置。


另请参阅:如何导入以字符串形式命名的模块?


当前回答

为了补充塞巴斯蒂安·里托的回答:至少对于CPython,有pydoc,虽然没有正式声明,但导入文件就是它的作用:

from pydoc import importfile
module = importfile('/path/to/module.py')

PS。为了完整起见,在撰写本文时,这里提到了当前的实现:pydoc.py,我很高兴地说,在xkcd 1987的脉络中,它没有使用第21436期中提到的任何一个实现,至少没有逐字逐句地使用。

其他回答

一种非常简单的方法:假设您希望导入具有相对路径../..的文件/MyLibs/pyfunc.py

libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf

但如果你在没有守卫的情况下成功,你最终会走上一条很长的路。

对于Python 3.5+,使用(docs):

import importlib.util
import sys
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
sys.modules["module.name"] = foo
spec.loader.exec_module(foo)
foo.MyClass()

对于Python 3.3和3.4,请使用:

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()

(尽管Python 3.4中已弃用此选项。)

对于Python 2,请使用:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

编译后的Python文件和DLL有等效的方便函数。

另请参见http://bugs.python.org/issue21436.

为了补充塞巴斯蒂安·里托的回答:至少对于CPython,有pydoc,虽然没有正式声明,但导入文件就是它的作用:

from pydoc import importfile
module = importfile('/path/to/module.py')

PS。为了完整起见,在撰写本文时,这里提到了当前的实现:pydoc.py,我很高兴地说,在xkcd 1987的脉络中,它没有使用第21436期中提到的任何一个实现,至少没有逐字逐句地使用。

这是我的两个仅使用pathlib的实用程序函数。它从路径推断模块名称。

默认情况下,它从文件夹中递归加载所有Python文件,并用父文件夹名替换init.py。但您也可以提供路径和/或glob来选择某些特定文件。

from pathlib import Path
from importlib.util import spec_from_file_location, module_from_spec
from typing import Optional


def get_module_from_path(path: Path, relative_to: Optional[Path] = None):
    if not relative_to:
        relative_to = Path.cwd()

    abs_path = path.absolute()
    relative_path = abs_path.relative_to(relative_to.absolute())
    if relative_path.name == "__init__.py":
        relative_path = relative_path.parent
    module_name = ".".join(relative_path.with_suffix("").parts)
    mod = module_from_spec(spec_from_file_location(module_name, path))
    return mod


def get_modules_from_folder(folder: Optional[Path] = None, glob_str: str = "*/**/*.py"):
    if not folder:
        folder = Path(".")

    mod_list = []
    for file_path in sorted(folder.glob(glob_str)):
        mod_list.append(get_module_from_path(file_path))

    return mod_list

您也可以执行类似的操作,将配置文件所在的目录添加到Python加载路径中,然后进行正常导入,假设您事先知道文件的名称,在本例中为“config”。

凌乱,但它有效。

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config