猴子补丁(Monkey Patching)是一种在运行时动态修改代码的技术,通常用于临时修复 bug、修改第三方库的行为,或给已有类/方法增加功能。
猴子补丁的核心
猴子补丁的本质就是修改已有模块、类、函数的实现,而不需要修改源代码。
示例 1:修改第三方库的行为
假设你在使用 math.sqrt
计算平方根时,想要修改它的行为,让它默认返回整数部分。
import math
# 打补丁前
print(math.sqrt(10)) # 正常返回 3.1622776601683795
# 给 math.sqrt 打猴子补丁
math.sqrt = lambda x: int(math.pow(x, 0.5))
# 打补丁后
print(math.sqrt(10)) # 只返回整数部分 3
示例 2:给类方法打补丁
假设你有一个 Person
类,但你想在运行时修改它的 say_hello
方法。
class Person:
def say_hello(self):
return "Hello, I'm a Person!"
# 原方法
p = Person()
print(p.say_hello()) # Hello, I'm a Person!
# 定义新方法
def new_say_hello(self):
return "Hi, I've been patched!"
# 给类方法打补丁
Person.say_hello = new_say_hello
# 现在实例调用的是新的方法
print(p.say_hello()) # Hi, I've been patched!
示例 3:给模块中的函数打补丁
假设你在测试时,想要修改 time.sleep
,避免代码真的暂停。
import time
# 原来的 sleep 会暂停执行
print("Before sleep")
time.sleep(2) # 真的会等待 2 秒
print("After sleep")
# 打补丁:让 time.sleep 变成不等待的函数
time.sleep = lambda x: None
print("Before fake sleep")
time.sleep(2) # 现在不会暂停了
print("After fake sleep")
猴子补丁的应用场景
- 修复 Bug:当你发现第三方库的 Bug,但无法修改源码时,可以临时修复它。
- 修改第三方库行为:有时候你不想修改源码,就可以动态修改它的函数/类。
- 测试模拟(Mocking):测试时可以修改某些函数的行为,避免不必要的操作(如
sleep
、网络请求等)。 - 动态扩展功能:给已有类/方法增加新功能,而不修改原始代码。
注意事项
⚠ 慎用猴子补丁,因为:
- 修改全局行为:可能影响整个程序,甚至破坏依赖它的代码。
- 难以调试:打补丁后,可能不容易追踪到错误来源。
- 版本兼容性问题:如果原始库更新,补丁可能失效。
更优雅的替代方案
如果你只想在特定情况下修改函数行为,可以使用 unittest.mock
:
from unittest.mock import patch
import time
with patch("time.sleep", return_value=None):
print("Before sleep")
time.sleep(2) # 这个 sleep 不会真的等待
print("After sleep")
这样,补丁只在 with
代码块内生效,出了 with
就恢复原始行为。
🐵 猴子补丁强大但危险,能用 Mock 就别直接改源码!