importlib — 导入的实现 — Python 文档
例子
以编程方式导入
要以编程方式导入模块,请使用 importlib.import_module()。
import importlib
itertools = importlib.import_module('itertools')
检查模块是否可以导入
如果您需要确定模块是否可以在不实际执行导入的情况下导入,那么您应该使用 importlib.util.find_spec()。
import importlib.util
import sys
# For illustrative purposes.
name = 'itertools'
if name in sys.modules:
print(f"{name!r} already in sys.modules")
elif (spec := importlib.util.find_spec(name)) is not None:
# If you chose to perform the actual import ...
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
print(f"{name!r} has been imported")
else:
print(f"can't find the {name!r} module")
直接导入源文件
要直接导入 Python 源文件,请使用以下方法(仅限 Python 3.5 和更新版本):
import importlib.util
import sys
# For illustrative purposes.
import tokenize
file_path = tokenize.__file__
module_name = tokenize.__name__
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
实现延迟导入
下面的例子展示了如何实现延迟导入:
>>> import importlib.util
>>> import sys
>>> def lazy_import(name):
... spec = importlib.util.find_spec(name)
... loader = importlib.util.LazyLoader(spec.loader)
... spec.loader = loader
... module = importlib.util.module_from_spec(spec)
... sys.modules[name] = module
... loader.exec_module(module)
... return module
...
>>> lazy_typing = lazy_import("typing")
>>> #lazy_typing is a real module object,
>>> #but it is not loaded in memory yet.
>>> lazy_typing.TYPE_CHECKING
False
设置进口商
对于导入的深度自定义,您通常希望实现一个 importer。 这意味着同时管理 finder 和 loader 方面。 对于查找器,有两种风格可供选择,具体取决于您的需要:元路径查找器或路径条目查找器。 前者是你会放在 sys.meta_path 上的东西,而后者是你在 sys.path_hooks 上使用 path entry hook 创建的东西,它与 一起使用]sys.path 条目可能会创建一个查找器。 此示例将向您展示如何注册您自己的导入器,以便导入使用它们(要为自己创建导入器,请阅读此包中定义的相应类的文档):
import importlib.machinery
import sys
# For illustrative purposes only.
SpamMetaPathFinder = importlib.machinery.PathFinder
SpamPathEntryFinder = importlib.machinery.FileFinder
loader_details = (importlib.machinery.SourceFileLoader,
importlib.machinery.SOURCE_SUFFIXES)
# Setting up a meta path finder.
# Make sure to put the finder in the proper location in the list in terms of
# priority.
sys.meta_path.append(SpamMetaPathFinder)
# Setting up a path entry finder.
# Make sure to put the path hook in the proper location in the list in terms
# of priority.
sys.path_hooks.append(SpamPathEntryFinder.path_hook(loader_details))
近似 importlib.import_module()
导入本身是用 Python 代码实现的,这使得通过 importlib 暴露大部分导入机制成为可能。 下面通过提供 importlib.import_module() 的近似实现来帮助说明 importlib 公开的各种 API(Python 3.4 和更新版本用于 importlib,Python 3.6 和更新版本用于代码的其他部分)。
import importlib.util
import sys
def import_module(name, package=None):
"""An approximate implementation of import."""
absolute_name = importlib.util.resolve_name(name, package)
try:
return sys.modules[absolute_name]
except KeyError:
pass
path = None
if '.' in absolute_name:
parent_name, _, child_name = absolute_name.rpartition('.')
parent_module = import_module(parent_name)
path = parent_module.__spec__.submodule_search_locations
for finder in sys.meta_path:
spec = finder.find_spec(absolute_name, path)
if spec is not None:
break
else:
msg = f'No module named {absolute_name!r}'
raise ModuleNotFoundError(msg, name=absolute_name)
module = importlib.util.module_from_spec(spec)
sys.modules[absolute_name] = module
spec.loader.exec_module(module)
if path is not None:
setattr(parent_module, child_name, module)
return module