sys.modules是模块缓存字典,核心作用是避免重复加载、保证单例性;每次import先查其键名,命中则直接返回模块对象,未命中才执行完整导入流程。

sys.modules 不是包管理器,它也不参与包的安装、解析或依赖解决。它对“包管理”之所以常被误认为重要,是因为它直接影响模块**是否被重复加载**和**如何被 import 语句命中**——这在开发调试、测试隔离、热重载等场景中容易引发实际问题。
import 时到底查什么?不是路径,是 sys.modules 键名
每次执行 import requests 或 from mypkg.sub import mod,Python 做的第一件事不是翻 sys.path,而是查 sys.modules 里有没有键 'requests' 或 'mypkg.sub'(注意:是字符串模块名,不是文件路径)。只有没命中,才走后续查找逻辑。
- 键名必须完全匹配:写
import mypkg后,sys.modules里存的是'mypkg',不是'mypkg.__init__';子模块mypkg.sub是独立键 - 包层级关系不体现在字典结构里:
sys.modules['mypkg']和sys.modules['mypkg.sub']是两个平行条目,没有嵌套 - 如果手动塞入
sys.modules['os'] = fake_os,后续所有import os都拿到 fake_os,不管真实os.py在哪
删 sys.modules 条目 ≠ 热重载,但它是重载的必要前提
改了 mymodule.py 想立刻生效?只删 sys.modules['mymodule'] 再 import mymodule,确实会触发重新执行顶层代码,但它不解决引用残留问题:
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
- 已有变量如
old_mod = mymodule仍指向旧对象,不会自动更新 - 类实例、已注册的信号回调、全局状态(比如
logging.getLogger()缓存)全都不变 - C 扩展模块(如
numpy)删键后重 import 可能失败,或导致内存泄漏/段错误 - 正确做法是配合
importlib.reload(),它内部先删键再重 import,但仍无法修复外部强引用
测试时 mock 包,靠的是往 sys.modules 塞假模块
单元测试里想让 import requests 返回 Mock,最轻量方式就是提前操作 sys.modules:
- 必须在任何真实
import requests之前执行:sys.modules['requests'] = Mock() - Mock 对象得有基本模块属性,至少设
__name__ = 'requests',否则导入机制会拒绝使用 - 不能只塞空
types.ModuleType('requests'),它缺少__dict__和协议方法,运行时报AttributeError - pytest 的
@patch('requests.get')底层也依赖这个机制,但自动处理了清理,手动操作需自己del sys.modules['requests']恢复
'mypackage' 在 sys.modules 里,不代表它能正常工作——可能只是个半初始化的空壳,__file__ 为 None,__path__ 没设,子模块根本导不进来。判断一个包“可用”,不能只查 sys.modules,得看它的实际属性是否健全。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










