惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
Security Latest
Security Latest
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
C
Cybersecurity and Infrastructure Security Agency CISA
Cloudbric
Cloudbric
T
Threat Research - Cisco Blogs
大猫的无限游戏
大猫的无限游戏
C
CXSECURITY Database RSS Feed - CXSecurity.com
阮一峰的网络日志
阮一峰的网络日志
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网
C
Cisco Blogs
V
Vulnerabilities – Threatpost
S
Security Archives - TechRepublic
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
J
Java Code Geeks
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Know Your Adversary
Know Your Adversary
博客园 - 叶小钗
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy International News Feed
P
Palo Alto Networks Blog
博客园_首页
V
V2EX
WordPress大学
WordPress大学
Schneier on Security
Schneier on Security
月光博客
月光博客
博客园 - 司徒正美
Google DeepMind News
Google DeepMind News
TaoSecurity Blog
TaoSecurity Blog
博客园 - 聂微东
酷 壳 – CoolShell
酷 壳 – CoolShell
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
The Cloudflare Blog
罗磊的独立博客
美团技术团队
N
News | PayPal Newsroom
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Last Week in AI
Last Week in AI
K
Kaspersky official blog
Google Online Security Blog
Google Online Security Blog
S
SegmentFault 最新的问题
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tailwind CSS Blog

又见苍岚

COLMAP PatchMatch Stereo 算法详解 事件驱动的状态机框架:从理论到工程实践 Git 在国内网络环境下无法 Push 的排查与修复 —— 配置 Clash 代理 分段五次多项式插值原理详解 路径插值方法深度对比研究 Claude Code 使用指南 OpenClaw 记忆管理与技能创建指南 CBS(Conflict-Based Search)算法详解 A* 算法及其变种详解 OpenClaw 配置多 Agents Windows Powershell 无法加载文件,因为在此系统上禁止运行脚本问题的解决方案 MaxClaw 安装流程 大模型 AI 名词介绍 AList 网盘聚合工具简介 Protobuf 简介与测试 Claude Code 简介以及 GLM 4.7 模型接入 Github 歌词下载工具 163MusicLyrics Python __getattr__ 懒加载 Python TypedDict 机器人仿真平台 Gazebo 安装记录 机器人仿真平台 Gazebo 简介 多机器人路径规划问题(Multi-Agent Path Finding, MAPF)简介 Python exifread 读取修改过的 jpeg 信息错误问题修复 3D 坐标系变换的理解 3D 旋转矩阵基本概念 MongoDB Compass 介绍 Python 环境管理工具 uv Flutter 开发指南 Snipaste 安装下载与黑屏问题解决方案 全局路径规划算法记录 2025 Python 版本性能测试 Flutter Hello World Flutter 安装环境配置 Ubuntu VMware 硬盘扩容后 SMBus Host controller not enabled 报错问题解决 Python NetworkX 教程 Docker GPU 报错 - Failed to initialize NVML Unknown Error 解决方案 Python matplotlib 图表绘制 cuda-toolkit 安装替代 Cuda 与 Cudnn Jinja2 Python 利用 docxtpl 和 Jinja2 生成基于模板的 Word 文档 Docker 实现 CPU 核心隔离 LoFTR 基于 Transformer 的特征提取匹配算法 OmniGlue 特征匹配 SuperGlue 使用图神经网络学习特征匹配 Ubuntu 下将 xlsx 文件按照 sheet 转换为 图片 Python 使用 SQLAlchemy Python FastAPI 教程 openwrt 软路由配置安装 Nav2 地图文件(PGM/YAML)规范标准 3D OBJ 模型转换为 glb 瓦片格式 Python 源码 Redis 数据库介绍 Ubuntu 22.04 内核自动升级导致 MongoDB 7.0.12 错误记录 ubuntu 20.04 安装 ROS Noetic ubuntu 18.04 安装 ROS Melodic VMware Workstation Pro 个人免费版下载、安装、使用指南 Hybrid A-star 路径规划 Reeds-Shepp 曲线 Dubins 曲线 Linux kvm 虚拟机网络不通的问题解决方法 Ubuntu 自动内存清理 BiliBili 缓存视频转 mp4 Python 求解线性规划 3D Gaussian Splatting 官方源码实践记录 ImageMagick 教程 Ubuntu 22.04 安装 Colmap 对数几率 odds Ubuntu nmcli 网络管理工具使用指南 SuperPoint 自监督深度学习特征点提取 SyncTV Music Tag Web 在线音乐信息整理工具 ncm 格式转 mp3 MusicBrainz 音乐元数据百科数据库 Ubuntu 网络流量监控工具 私人云音乐平台 Navidrome 入门 手眼标定 四元数(Quaternions) OHTTPS 实现免费自动 https 证书申请、更新、部署 ubuntu 22.04 安装 CloudCompare 单机 KVM 虚拟机冷迁移 Ubuntu 22.04 使用 mdadm 实现软 raid 小鱼 一键安装 ROS-humble Fluid -46- 基于 Simpletex API 构建公式识别页面 公式识别 API 简介 -- Simpletex 使用 Python web 部署库 waitress 3D Gaussian Splatting for Real-Time Radiance Field Rendering Ubuntu Swap 简介与空间扩展 Ubuntu 24.04 安装 forticlient Clash Verge 使用 MongoDB 7.0.17 集群 Docker 构建源码 Error code - 2013. Lost connection to MySQL server during query 问题解决 Python 日志记录库 loguru 使用指北 Python 实现 Web 日志查看服务 MySQL LOAD DATA LOCAL INFILE 极速数据加载 Image size exceeds limit of 89478485 pixels 解决方案 Docker 使用 NVIDIA GPU 驱动错误解决 阿里云 docker 镜像仓库 Ubuntu中没有wired connected的解决方案 MinIO 简介 subconverter 代理订阅格式转换 修复 node –openssl-legacy-provider is not allowed in NODE_OPTIONS 错误
Python importlib
Yiwei Zhang · 2025-01-23 · via 又见苍岚

本文介绍用于引入包的 Python importlib 库。

简介

importlib 包具有三重目标。

  1. 在 Python 源代码中提供 import 语句的实现(并且因此而扩展 import() 函数)。 这提供了一个可移植到任何 Python 解释器的 import 实现。 与使用 Python 以外的编程语言实现的方式相比这一实现也更易于理解。

  2. 实现 import 的部分被公开在这个包中,使得用户更容易创建他们自己的自定义对象 (通常被称为 importer) 来参与到导入过程中。

  3. 这个包也包含了对外公开用于管理 Python 包的各个方面的附加功能的模块:

    • importlib.metadata 代表对来自第三方发行版的元数据的访问。
    • importlib.resources 提供了用于对来自 Python 包的非代码“资源”的访问的例程。

下面介绍 importlib 的函数

importlib.import_module(name, package=None)

导入一个模块。 参数 name 指定了以绝对或相对导入方式导入什么模块 (比如要么像这样 pkg.mod 或者这样 ..mod)。 如果参数 name 使用相对导入的方式来指定,那么 package 参数必须设置为那个包名,这个包名作为解析这个包名的锚点 (比如 import_module('..mod', 'pkg.subpkg') 将会导入 pkg.mod)。

import_module() 函数是一个对 importlib.import() 进行简化的包装器。 这意味着该函数的所有语义都来自于 importlib.import()。 这两个函数之间最重要的不同点在于 import_module() 返回指定的包或模块 (例如 pkg.mod),而 import() 返回最高层级的包或模块 (例如 pkg)。

importlib.invalidate_caches()

使查找器存储在 sys.meta_path 中的内部缓存无效。如果一个查找器实现了 invalidate_caches(),那么它会被调用来执行那个无效过程。 如果创建/安装任何模块,同时正在运行的程序是为了保证所有的查找器知道新模块的存在,那么应该调用这个函数。

importlib.reload(module)

重新加载之前导入的 module。 那个参数必须是一个模块对象,所以它之前必须已经成功导入了。 这在你已经使用外部编辑器编辑过了那个模块的源代码文件并且想在退出 Python 解释器之前试验这个新版本的模块的时候将很适用。 函数的返回值是那个模块对象(如果重新导入导致一个不同的对象放置在 sys.modules 中,那么那个模块对象是有可能会不同)。

当执行 reload() 的时候:

  • Python 模块的代码会被重新编译并且那个模块级的代码被重新执行,通过重新使用一开始加载那个模块的 loader,定义一个新的绑定在那个模块字典中的名称的对象集合。扩展模块的 init 函数不会被调用第二次。

  • 与Python中的所有的其它对象一样,旧的对象只有在它们的引用计数为0之后才会被回收。

  • 模块命名空间中的名称重新指向任何新的或更改后的对象。

  • 其他旧对象的引用(例如那个模块的外部名称)不会被重新绑定到引用的新对象的,并且如果有需要,必须在出现的每个命名空间中进行更新。

importlib.abc

源代码: Lib/importlib/abc.py

importlib.abc 模块包含了 import 使用到的所有核心抽象基类。在实现核心的 ABCs 中,核心抽象基类的一些子类也提供了帮助。

ABC 类的层次结构:

1
2
3
4
5
6
7
8
9
object
+-- MetaPathFinder
+-- PathEntryFinder
+-- Loader
+-- ResourceLoader --------+
+-- InspectLoader |
+-- ExecutionLoader --+
+-- FileLoader
+-- SourceLoader

class importlib.abc.MetaPathFinder

一个代表 meta path finder 的抽象基类。

  • find_spec(fullname, path, target=None)

    一个用于查找指定模块的 spec 的抽象方法。 如果这是最高层级的导入,path 将为 None。 在其他情况下,这将是对子包或模块的搜索而 path 将是来自上级包的 path 值。 如果找不到 spec,则返回 None。 在传入时,target 是一个被查找器用来对返回的 spec 进行更有依据的猜测的模块对象。 在实现具体 MetaPathFinders 的时候 importlib.util.spec_from_loader() 将会很有用处。

  • invalidate_caches()

    当被调用的时候,一个可选的方法应该将查找器使用的任何内部缓存进行无效。将在 sys.meta_path 上的所有查找器的缓存进行无效的时候,这个函数被 importlib.invalidate_caches() 所使用。

class importlib.abc.PathEntryFinder

一个抽象基类,代表 path entry finder。虽然与 MetaPathFinder 有些相似之处,但 PathEntryFinder 仅用于 importlib.machinery.PathFinder 提供的基于路径的导入子系统中。

  • find_spec(fullname, target=None)

    一个抽象方法,用于查找指定模块的 spec。搜索器将只在指定的 path entry 内搜索该模块。找不到则会返回 None。在实现具体的 PathEntryFinders 代码时,可能会用到 importlib.util.spec_from_loader() 。

  • invalidate_caches()

    可选方法,调用后应让查找器用到的所有内部缓存失效。要让所有缓存的查找器的缓存无效时,可供 importlib.machinery.PathFinder.invalidate_caches() 调用。

class importlib.abc.Loader

loader 的抽象基类。

想要支持资源读取的加载器应当实现 importlib.resources.abc.ResourceReader 所规定的 get_resource_reader() 方法。

  • create_module(spec)

    当导入一个模块的时候,一个返回将要使用的那个模块对象的方法。这个方法可能返回 None ,这暗示着应该发生默认的模块创建语义。"

  • exec_module(module)

    当一个模块被导入或重新加载时在自己的命名空间中执行该模块的的抽象方法。 该模块在 exec_module() 被调用时应该已经被初始化了。 当此方法存在时,必须要定义 create_module()。

  • load_module(fullname)

    用于加载模块的传统方法。 如果模块无法被导入,则会引发 ImportError,在其他情况下将返回被加载的模块。

    如果请求的模块已存在于 sys.modules 中,则该模块应当被使用并重新加载。 在其他情况下加载器应当创建一个新模块并在任何加载操作开始之前将其插入到 sys.modules 中,以防止来自导入的无限递归。 如果加载器插入了一个模块并且加载失败,则必须用加载器将其从 sys.modules 中移除;在加载器开始执行之前已经存在于 sys.modules 中的模块应当保持原样。

class importlib.abc.InspectLoader

  • get_code(fullname)

    返回一个模块的代码对象,或如果模块没有一个代码对象(例如,对于内置的模块来说,这会是这种情况),则为 None。 如果加载器不能找到请求的模块,则引发 ImportError 异常。

  • is_package(fullname)

    可选方法,如果模块为包,则返回 True,否则返回 False。 如果 loader 找不到模块,则会触发 ImportError。

class importlib.abc.FileLoader(fullname, path)

一个继承自 ResourceLoader 和 ExecutionLoader,提供 ResourceLoader.get_data() 和 ExecutionLoader.get_filename() 具体实现的抽象基类。

  • name

    加载器可以处理的模块的名字。

  • path

    模块的文件路径

  • load_module(fullname)

    调用super的 load_module()

class importlib.abc.SourceLoader

一个用于实现源文件(和可选地字节码)加载的抽象基类。

  • path_stats(path)

    返回一个包含关于指定路径的元数据的 dict 的可选的抽象方法。 支持的字典键有:

    • 'mtime' (必选项): 一个表示源码修改时间的整数或浮点数;
    • 'size' (可选项):源码的字节大小。
  • path_mtime(path)

    返回指定文件路径修改时间的可选的抽象方法。

  • set_data(path, data)

    往一个文件路径写入指定字节的的可选的抽象方法。任何中间不存在的目录不会被自动创建。

class importlib.abc.Traversable

一个具有 pathlib.Path 中方法的子集并适用于遍历目录和打开文件的对象。

  • name

    抽象属性。 此对象的不带任何父引用的基本名称。

  • abstractmethod iterdir()

    产出 self 中的 Traversable 对象。

  • abstractmethod is_dir()

    如果 self 是一个目录则返回 True。

  • abstractmethod is_file()

    如果 self 是一个文件则返回 True。

  • abstractmethod joinpath(child)

    返回 self 中的 Traversable 子对象。

  • abstractmethod truediv(child)

    返回 self 中的 Traversable 子对象。

  • abstractmethod open(mode=‘r’, args, kwargs)

    mode 可以为 ‘r’ 或 ‘rb’ 即以文本或二进制模式打开。 返回一个适用于读取的句柄(与 pathlib.Path.open 样同)。

    当以文本模式打开时,接受与 io.TextIOWrapper 所接受的相同的编码格式形参。

  • read_bytes()

    以字节串形式读取 self 的内容。

  • read_text(encoding=None)

    以文本形式读取 self 的内容。

importlib.util

导入器的工具程序代码

importlib.util.MAGIC_NUMBER

代表字节码版本号的字节串。

importlib.util.cache_from_source(path, debug_override=None, optimization=None)

返回源 path 相关联的已编译字节码文件的路径。

importlib.util.source_from_cache(path)

根据指向一个文件名的 path,返回相关联的源代码文件路径。 举例来说,如果 path 为 /foo/bar/pycache/baz.cpython-32.pyc 则返回的路径将是 /foo/bar/baz.py。 path 不需要已存在,但如果它未遵循 PEP 3147 或 PEP 488 的格式,则会引发 ValueError。 如果未定义 sys.implementation.cache_tag,则会引发 NotImplementedError。

importlib.util.decode_source(source_bytes)

对代表源代码的字节串进行解码,并将其作为带有通用换行符的字符串返回(符合 importlib.abc.InspectLoader.get_source() 要求)。

importlib.util.resolve_name(name, package)

将模块的相对名称解析为绝对名称。

如果 name 前面没有句点,那就简单地返回 name。这样就能采用 importlib.util.resolve_name(‘sys’, spec.parent) 之类的写法,而无需检查是否需要 package 参数。

如果 name 是一个相对模块名称但 package 为假值(如为 None 或空字符串)则会引发 ImportError。 如果相对名称离开了其所在的包(如为从 spam 包请求 …bacon 的形式)则也会引发 ImportError。

importlib.util.find_spec(name, package=None)

查找模块的 spec,可选择相对于指定的 package 名称。 如果该模块位于 sys.modules 中,则会返回 sys.modules[name].spec (除非 spec 为 None 或未设置,在此情况下则会引发 ValueError)。 在其他情况下将使用 sys.meta_path 进行搜索。 如果找不到任何 spec 则返回 None。

如果 name 为一个子模块(带有一个句点),则会自动导入父级模块。

name 和 package 的用法与 import_module() 相同。

importlib.util.module_from_spec(spec)

基于 spec 和 spec.loader.create_module 创建一个新模块。

如果 spec.loader.create_module 未返回 None,那么先前已存在的属性不会被重置。另外,如果 AttributeError 是在访问 spec 或设置模块属性时触发的,则不会触发 。

本函数比 types.ModuleType 创建新模块要好,因为用到 spec 模块设置了尽可能多的导入控制属性。

importlib.util.spec_from_loader(name, loader, *, origin=None, is_package=None)

一个工厂函数,用于创建基于加载器的 ModuleSpec 实例。参数的含义与 ModuleSpec 的相同。该函数会利用当前可用的 loader API,比如 InspectLoader.is_package(),以填充所有缺失的规格信息。

importlib.util.spec_from_file_location(name, location, *, loader=None, submodule_search_locations=None)

一个工厂函数,根据文件路径创建 ModuleSpec 实例。缺失的信息将根据 spec 进行填补,利用加载器 API ,以及模块基于文件的隐含条件。

importlib.util.source_hash(source_bytes)

以字节串的形式返回 source_bytes 的哈希值。基于哈希值的 .pyc 文件在头部嵌入了对应源文件内容的 source_hash()。

importlib.util._incompatible_extension_module_restrictions(*, disable_check)

一个可以暂时跳过扩展模块兼容性检查的上下文管理器。 在默认情况下该检查将被启用并且当在子解释器中导入单阶段初始化模块时该检查会失败。 如果多阶段初始化模块没有显式地支持针对子解释器的 GIL,那么当它在一个有自己的 GIL 的解释器中被导入时,该检查也会失败。

请注意该函数是为了适应一种不寻常的情况;这种情况可能最终会消失。 这很有可能不是你需要考虑的事情。

class importlib.util.LazyLoader(loader)

此类会延迟执行模块加载器,直至该模块有一个属性被访问到。

此类 仅仅 适用于定义 exec_module() 作为需要控制模块使用何种模块类型的加载器。 出于相同理由,加载器的 create_module() 方法必须返回 None 或其 class 属性可被改变并且不使用 槽位 的类型。 最后,用于替换已放入 sys.modules 的对象的模块将无法工作因为没有办法安全地在整个解释器中正确替换模块引用; 如果检测到这种替换则会引发 ValueError。

class importlib.util.LazyLoader(loader)

此类会延迟执行模块加载器,直至该模块有一个属性被访问到。

此类 仅仅 适用于定义 exec_module() 作为需要控制模块使用何种模块类型的加载器。 出于相同理由,加载器的 create_module() 方法必须返回 None 或其 class 属性可被改变并且不使用 槽位 的类型。 最后,用于替换已放入 sys.modules 的对象的模块将无法工作因为没有办法安全地在整个解释器中正确替换模块引用; 如果检测到这种替换则会引发 ValueError。

  • classmethod factory(loader)

    一个返回创建延迟加载器的可调用对象的类方法。 这专门被用于加载器由类而不是实例来传入的场合。

举例

用编程方式导入

要以编程方式导入一个模块,请使用 importlib.import_module()

1
2
3
import importlib

itertools = importlib.import_module('itertools')

检查某模块可否导入

如果你需要在不实际执行导入的情况下确定某个模块是否可被导入,则你应当使用 importlib.util.find_spec()。

请注意如果 name 是一个子模块(即包含一个点号),则 importlib.util.find_spec() 将会导入父模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import importlib.util
import sys

# 出于展示目的。
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:
# 如果你选择执行实际的导入 ...
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")

直接导入源码文件

这个专用方案应当谨慎使用:它是直接指明文件路径而不搜索 sys.path 的 import 语句的近似物。 应当首先考虑其他替代方案,比如在需要某个特定模块时修改 sys.path,或在运行某个 Python 得到正确的全局命名空间时使用 runpy.run_path()。

要直接从某个路径导入 Python 源文件,请使用以下写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import importlib.util
import sys

def import_from_path(module_name, file_path):
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)
return module

# 仅用于演示目的 (`json` 是随意选择的)。
import json
file_path = json.__file__
module_name = json.__name__

# 结果与 `import json` 类似。
json = import_from_path(module_name, file_path)

实现延迟导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

导入器的配置

对于导入的深度定制,通常你需要实现一个 importer。 这意味着同时管理 finder 和 loader 两方面。 对于查找器来说根据你的需求有两种类别可供选择: meta path finder 或 path entry finder。 前者你应当放到 sys.meta_path 而后者是使用 path entry hook 在 sys.path_hooks 上创建并与 sys.path 条目一起创建一个潜在的查找器。 下面的例子将向你演示如何注册自己的导入器供导入机制使用 (关于自行创建导入器,请阅读在本包内定义的相应类的文档):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import importlib.machinery
import sys

# 仅用于展示目的。
SpamMetaPathFinder = importlib.machinery.PathFinder
SpamPathEntryFinder = importlib.machinery.FileFinder
loader_details = (importlib.machinery.SourceFileLoader,
importlib.machinery.SOURCE_SUFFIXES)

# 设置一个元路径查找器。
# 确保根据优先级别将查找器放在列表中正确的位置上。
sys.meta_path.append(SpamMetaPathFinder)

# 设置一个路径条目查找器。
# 确保根据优先级别将路径钩子放在列表中正确的位置上。
sys.path_hooks.append(SpamPathEntryFinder.path_hook(loader_details))

importlib.import_module() 的近似实现

导入过程本身是用 Python 代码实现的,这样就有可能通过 importlib 来对外公开大部分导入机制。 以下代码通过提供 importlib.import_module() 的近似实现来说明 importlib 所公开的几种 API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import importlib.util
import sys

def import_module(name, package=None):
"""导入的近似实现。"""
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

参考资料

文章链接:
https://www.zywvvd.com/notes/coding/python/python-importlib/python-importlib/