如何加载给定完整路径的Python模块?
请注意,文件可以位于文件系统中用户具有访问权限的任何位置。
另请参阅:如何导入以字符串形式命名的模块?
如何加载给定完整路径的Python模块?
请注意,文件可以位于文件系统中用户具有访问权限的任何位置。
另请参阅:如何导入以字符串形式命名的模块?
当前回答
这是我的两个仅使用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
其他回答
你的意思是装货还是进口?
您可以操作sys.path列表,指定模块的路径,然后导入模块。例如,给定位于以下位置的模块:
/foo/bar.py
你可以这样做:
import sys
sys.path[0:0] = ['/foo'] # Puts the /foo directory at the start of your path
import bar
我相信您可以使用imp.find_module()和imp.load_module)来加载指定的模块。您需要将模块名称从路径中分离出来,即,如果要加载/home/mypath/mymodule.py,则需要执行以下操作:
imp.find_module('mymodule', '/home/mypath/')
…但这应该能完成任务。
向sys.path添加路径(与使用imp相比)的优点是,当从单个包导入多个模块时,可以简化操作。例如:
import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')
from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch
我对@SebastianRittau的精彩回答(我认为Python>3.4)做了一个稍微修改的版本,它允许您使用spec_from_loader而不是spec_from_file_location加载具有任何扩展名的文件作为模块:
from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader
spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
mod = module_from_spec(spec)
spec.loader.exec_module(mod)
在显式SourceFileLoader中编码路径的优点是,机器不会试图从扩展名中找出文件的类型。这意味着您可以使用此方法加载类似.txt文件的文件,但如果不指定加载器,则无法使用spec_from_file_location加载,因为.txt不在importlib.machinery.SOURCE_SUFFIX中。
我已经在此基础上放置了一个实现,@SamGrondahl对我的实用程序库haggis进行了有用的修改。该函数名为hagis.load.load_module。它添加了一些巧妙的技巧,例如在加载模块时将变量注入模块命名空间的能力。
对于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.