猴子补丁

猴子补丁

  1. 在运行时替换方法、属性等,动态属性替换

  2. 在不修改第三方代码的情况下增加原来不支持的功能

  3. 在运行时为内存中的对象增加patch而不是在磁盘的源代码中增加

  4. 主要用途在于源码不宜直接修改,而添加补充功能

  5. 例子:python自带的json包不支持自定义对象转json串,在python中用json.dumps转自定义对象时会报异常class is not JSON serializable,通过增加一段代码补丁(称作猴子补丁)便可实现自定义转换,补丁代码如下:

 1 import re
 2 old_match = re.match # 保留旧函数,后面可以直接用
 3 ​
 4 def new_match(*args, **kwargs):
 5     print('re.match is running') # 增加自己的逻辑
 6     return old_match(*args, **kwargs) # 调用回旧函数
 7 ​
 8 re.match = new_match # 使用新的函数地址替换旧的函数地址
 9 ​
10 # 一个全新的函数
11 def hello(*args, **kwargs):
12     print(args, kwargs)
13 re.hello = hello # 赋予一个新属性(函数)
14 ​
15 """
16 >>> re.match('.*', 'abc')
17 re.match is running # 如果没有 patch,此行不会输出
18 <re.Match object; span=(0, 3), match='abc'>
19 >>> re.hello(123) # 如果没有 patch,调用这个函数会报错
20 (123,) {}
21 """
 1 from json import JSONEncoder
 2     """
 3     自定义_default补丁方法,传入对象
 4     先判断传入的对象中有没有to_json属性,如果没有,则走对象默认的方法,若有则走to_json
 5     """
 6     def _default(self, obj):
 7         return getattr(obj.__class__, "to_json", JSONEncoder().default)(obj)
 8     JSONEncoder.default = _default
 9     
10 class Tmp:
11     def __init__(self, id, name):
12         self.id = id
13         self.name = name
14 ​
15     def to_json():
16         # 返回自定义对象json串
17         pass   

通过补丁代码我们可以看到,代码替换了json包的默认转json的方法,运行了补丁代码后,转json的过程变成了先找对象的to_json属性,在没有to_json属性的情况下才使用默认的JSONEncoder.default的方法,也就是通过这么一个patch,增加了json包原来没有的功能。同时也不影响其他调用者使用JSONEncoder.default的方法(推荐这么写,降低改变源代码的风险)

猴子补丁与装饰器的区别

作用时期不同:猴子补丁作用于运行时,装饰器作用于定义时

由于猴子补丁是直接用新的函数地址覆盖源代码的函数地址,所以需要慎用

上一篇:C++正则表达式


下一篇:SaaS数据模型