HMR¶
Real hot-module reload for Python—side effects handled reactively.
Hot Module Reload,简称 HMR,起源于前端的 Webpack。但在 Python 世界里,我们一直只有笨重的"冷重启"——杀进程,重新加载所有模块,丢失运行时状态。我写这个库就是想改变这一点。
核心思路:不是重启整个进程,而是追踪哪些模块/变量被谁依赖,只重新执行真正受影响的部分。
The elevator pitch
hmr main.py 替代 python main.py,告别冷重启。编辑代码,瞬间生效。
Why HMR¶
传统方案如 watchfiles CLI 或 uvicorn 的 --reload,本质都是检测文件变化后杀掉进程重启。对于加载大模型、建立数据库连接这类耗时初始化的应用来说,这简直是噩梦。
HMR 不同:
- 改了哪个模块,就只重新执行那个模块
- 依赖这个模块的代码会被自动通知并重算
- 第三方库、配置加载等不受影响的部分保持原样
而且,不像 Tach 这类静态分析工具,HMR 是**运行时追踪**依赖的——通过一套我自己写的反应式系统。
How It Works¶
整个系统分两层:
Reactivity Layer¶
底层是一套类似 SolidJS 的 push-pull 反应式框架:
Signal是最基本的可订阅值,变化时推送通知Derived是惰性计算的派生值,被拉取时才重算Effect是副作用,订阅的值变化时自动重跑Batch把多个变更合并,避免级联触发
from reactivity import signal, derived, effect
count = signal(0)
doubled = derived(lambda: count() * 2)
effect(lambda: print(f"doubled: {doubled()}")) # prints: doubled: 0
count.set(1) # prints: doubled: 2
count.set(2) # prints: doubled: 4
这套 API 命名融合了 Svelte 5 和 SolidJS 的风格。我还加了 async_effect、async_derived 支持异步,以及 new_context() 做上下文隔离。
Module Layer¶
模块层的魔法在于 ReactiveModule:
- 通过 meta-path finder 拦截 import
- 把模块的 namespace 包装成
NamespaceProxy,每次__getattr__都会 track 依赖 - 用
sys.addaudithook监控文件读取,建立文件→模块的映射 - 文件变化时,watchfiles 通知我们,触发对应模块的 invalidation
这样,模块之间的依赖图就在运行时自动构建起来了。不需要静态分析 AST,因为实际运行过程中谁访问了谁,我们都知道。
My Clever Bits¶
- 变量级细粒度:大多数热重载方案是模块级的,我做到了变量级。如果只改了某个函数,只有真正用到这个函数的地方会重算
- push-pull 混合:纯 push 会导致不必要的重算,纯 pull 要轮询。我的实现是 push invalidation + lazy recompute,只有被 Effect 拉取的 Derived 才会急切求值
- AST 魔改绕过 CPython bug:我之前给 CPython 提了个 issue,class 定义里访问全局变量时,自定义的 dict 子类不会被正确查询。为了让函数级热重载支持 class 定义,我用 AST 变换绕过了这个问题
.pth守护模式:装个hmr-daemon包,往 site-packages 扔个.pth文件,不改代码也能让普通 Python 脚本支持热重载
Usage¶
CLI¶
最简单的用法:
hmr main.py
# or
hmr -m mymodule
就像 python 命令一样,但文件改动会自动热重载。
With uvicorn¶
用 uvicorn-hmr 替代 uvicorn CLI,给 FastAPI/Starlette 应用加上真正的 HMR:
uvicorn-hmr app:app --refresh # --refresh 还能自动刷新浏览器
Daemon Mode¶
装了 hmr-daemon 后,直接 python script.py 就能热重载——通过 .pth 文件在 Python 启动时注入。
MCP Server¶
最近还做了 mcp-hmr,把 HMR 文档暴露给 AI agents。Cursor、Claude Code 这些工具可以直接查 HMR 的用法和源码。
Related Projects¶
- breuleux/jurigged:老牌热重载方案,轻量但不是线程安全的
- reloadware/reloadium:功能丰富,支持 Django/Flask/Pandas,但比较重
- python-hmr:同名老项目,早已停止维护,用起来很麻烦
HMR 更像是把前端 Vite 的开发体验带到 Python。
Development Only
HMR 是开发工具,不要用在生产环境。
Source Dive¶
- reactivity/primitives.py:反应式原语实现
- reactivity/hmr/core.py:模块热重载核心逻辑
- reactivity/hmr/fs.py:文件系统监听
- llms.txt:LLM 友好的文档格式