直接回答:猴子补丁指在运行时直接替换模块、类或对象的属性(方法、函数、常量),利用 Python「属性查找发生在运行时」的动态特性,不改源码就改变行为。它强大但隐式,是典型的"能力越大责任越大"的语言特性。
import requests
def fake_get(url, **kw):
return {"mocked": True}
requests.get = fake_get # 运行时替换
# 本进程内之后所有 requests.get(...) 调用都走 fake_get
展开解析:典型用途有三类。一是测试打桩:unittest.mock.patch 和 pytest 的 monkeypatch fixture 本质上都是受控的猴子补丁,后者在用例结束后自动还原,避免污染其他测试。二是热修复:线上紧急绕过第三方库的 bug,等不及上游发版。三是运行时改造:gevent/eventlet 的 monkey.patch_all() 把标准库的 socket、select、threading 换成协程友好版本,让同步代码自动获得异步调度能力——它必须在任何网络模块被导入之前调用,否则已创建的连接和已导入的引用不会被替换。
风险与对策:补丁是全局生效的,一处打、处处变,排查问题时很难想到"行为被运行时改过";类型检查器看不到补丁,签名可能对不上;被补丁的库升级后内部结构变化,补丁会静默失效甚至引入新 bug。生产代码应优先用依赖注入、子类化或包装层,把猴子补丁限制在测试和确有必要的热修复中,集中登记并写明原因与回退条件。
追问方向:monkeypatch.setattr 和 mock.patch 的作用域与还原机制有什么区别?patch 的目标路径为什么要写"被使用处"而不是"被定义处"?
(约 540 字)