importlib — 导入的实现 — Python 文档

世界杯开始 2025-10-26 16:21:53

例子

以编程方式导入

要以编程方式导入模块,请使用 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