27.Python中的猴子补丁 (Monkey Patching)
《Python编程的术与道:Python语言进阶》视频课程
《Python编程的术与道:Python语言进阶》视频课程链接:https://edu.csdn.net/course/detail/28618
猴子补丁 (Monkey Patching)
猴子补丁是一项允许在运行时(runtime)更改对象行为的技术。 它是一个非常有用的功能,但它也可能使你的代码更难以理解和调试,因此,在实现猴子补丁程序时必须谨慎。
猴子补丁与Python中的灵活性紧密相关。 自定义对象是可变的,因此可以替换其属性而无需创建该对象的新副本。
来看一个例子:
class A:def speak(self):return "hello"def speak_patch(self):return "world"
A.speak = speak_patch # <1>
some_class = A()
print('some_class.speak():', some_class.speak()) # <2>
some_class.speak(): world
<2>的部分会显示 world,而不会显示 hello,原因是因为我们在 <1> 的部分做了猴子补丁,即使用speak_patch 这个函数去取代掉原来的speak。
再来看一个例子:
class A:def __init__(self, array):self._list = array# def __len__(self): # <2># return len(self._list)def length(obj): # <1>return len(obj._list) # <2>A.__len__ = length # <3>a = A([1, 2, 3])
print('length:', len(a))
length: 3
A class 并没有定义 __len__
的方法 ( 将 <2> 注释起来 ),如果是在 runtime 中,我们可不可以把 __len__
方法加上去?
可以,只要将 <1> 的部分的 function 先写出来。注意:该有的参数还是要有,但名称可以不一样,像是原本 <2> 是 self,在 <1> 可以任意写 ( 例如 obj ),因为会在 <3> 的部分自己去对应起来。但是取长度时,也就是 <2> 的部分,就必须要写 obj._list,
经过以上的部分,就可以成功的在 runtime 时,实际上实现A class 的 __len__
。那为什么不一开始就实现 __len__
,像是:
class A:def __init__(self, array):self._list = arraydef __len__(self): # <2>return len(self._list)
原因是我们不希望去修改 A class 的源代码,而后者的修改也只是暂时性的,像用在测试时。
Python 中的猴子补丁是有限制的,它限制你不能给内置类型打补丁。比如要给str这个对象打补丁,就会报错。
def find(self, sub, start=None, end=None):return 'ok'str.find = find
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-7-f3f01b37ba7a> in <module>2 return 'ok'3
----> 4 str.find = findTypeError: can't set attributes of built-in/extension type 'str'
原因是可以保证内置的功能都是原本的,避免有人去打补丁后,导致后续一堆奇怪的问题。
记得,猴子补丁不能滥用,否则会造成系统难以维护以及代码很难理解。
types module 中的 types.MethodType
很类似猴子补丁,来看一个 types.MethodType 的例子,
import typesclass A:def speak(self):return "hello"def speak_patch(self):return "world"a = A()
a.speak = types.MethodType(speak_patch, a) # <1>
print('a.speak():', a.speak()) # <2>a2 = A()
print('a2.speak():', a2.speak()) # <3>
a.speak(): world
a2.speak(): hello
<1> 的部分,使用方法 types.MethodType( fun, obj)。要注意的是,我们是放一个 instance (a) 进去,所以 <2> 的输出是 world,而 <3> 的输出则是 hello ( 因为 a2 的 instance 我们并没有去修改 )。
再来看一个例子:
import typesclass A:def speak(self):return "hello"def speak_patch(self):return "world"A.speak = types.MethodType(speak_patch, A) # <1>
a = A()
print('a.speak():', a.speak()) # <2>a2 = A()
print('a2.speak:', a2.speak()) # <3>
a.speak(): world
a2.speak: world
<1> 的部分,我们是放一个 A class 进去,所以 <2> 和 <3> 的输出都会是 world,因为我们改变了 A class,这几乎就和前面所介绍的猴子补丁是一样的功能。
这里主要是强调 patched instance或是patched class是不太一样的。
模块级别的猴子补丁
在模块级别也可以用猴子补丁。
#module.py
def print_variable(var):print(var)
# module2.py
import moduledef another_print(var):module.print_variable(var+1)
#script.py
import module
import module2var1 = 1module.print_variable(var1)
# 1def print_plus_one(var):print(var+1)module.print_variable = print_plus_onemodule.print_variable(var1)
# 2
module2.another_print(var1)
# 3
1
2
3
什么时候用去猴子补丁?
猴子补丁非常强大,它显示了Python的灵活性。
作为一般规则,最好不要打猴子补丁。例如,如果要更改程序的行为,则可以为要更改的类定义子类。猴子补丁的问题在于程序的行为变得更加难以理解。要追溯行为的变化变得非常复杂。
但是,有时可能会有很大的好处。例如,使用numpy计算快速傅里叶变换可能比使用其他实现慢。想象一下你想使用PyFFTW,但是不想重写所有程序。这时你可以猴子补丁你的代码!
请参阅下面的示例:
import pyfftw
import numpynumpy.fft = pyfftw.interfaces.numpy_fft
现在,无论何时使用numpy提供的FFT例程,它们都会被PyFFTW的例程自动替换。这可能会对你的程序产生巨大的影响,并且只用了一行代码!
另外,常见的情况是测试。有时,你想在缺乏某些功能的环境中测试代码,或者由于测试实际上是在修改实时数据库,因此想防止这种情况。在这种情况下,可以在进行测试之前更改与数据库通信的方法。 即在测试程序时先避免与设备通信。
总之,究竟如何实现此行为将取决于具体情况。
27.Python中的猴子补丁 (Monkey Patching)相关推荐
- python的猴子补丁(Monkey Patching)
0. 参考文档 参考文档如下: https://achowdhary.com/monkey-patching/ https://www.cnblogs.com/xp1315458571/p/16049 ...
- 猴子补丁 - Monkey Patching
0 猴子补丁 - Monkey Patching 1 定义, 2 猴子补丁(monkey patching) 3 在运行时动态修改模块.类或函数,通常是添加功能或修正缺陷.猴子补丁在代码运行时 4 ( ...
- 猴子补丁(Monkey Patching)
猴子补丁是我在面试的时候接触的一到题,学python的时候,我根本就没有听说这个概念!那接下来我们来分析一下: 1.什么是猴子补丁? 2.猴子补丁的功能? 3.猴子补丁的应用场景? 一.什么是猴子补丁 ...
- python画猴子_Python猴子补丁Monkey Patch用法实例解析
属性在运行时的动态替换,叫做猴子补丁(Monkey Patch). 为什么叫猴子补丁 属性的运行时替换和猴子也没什么关系,关于猴子补丁的由来网上查到两种说法: 1.这个词原来为Guerrilla Pa ...
- python猴子补丁_Python猴子补丁Monkey Patch用法实例解析
属性在运行时的动态替换,叫做猴子补丁(Monkey Patch). 为什么叫猴子补丁 属性的运行时替换和猴子也没什么关系,关于猴子补丁的由来网上查到两种说法: 1.这个词原来为Guerrilla Pa ...
- python设计模式之猴子补丁模式
1.所有书中都没有把猴子补丁作为一种设计模式来看待.因为设计模式的模式的命名是根据java中提炼出来的,语言方式决定了java绝对不会有也不需要有这种操作,不存在的.那自然设计模式不会包括猴子补丁模式 ...
- 【华为云技术分享】python教程:猴子补丁
猴子补丁指在运行时修改类或者模块,而不是改动定义类或者模块的源代码. 假设有预先定义的类A: class Apple:def __init__(self):self._color = 'red'def ...
- python中模块打补丁
前言:今天接触到一个常听的名词也感觉很深奥的词语,补丁,有点好奇就来研究研究 假定现在有模块一和模块二,想调用模块二中的一个方法,但是不小心写成了模块一中的方法,在不大浮动 改动主程序代码的前提下,通 ...
- 什么是猴子补丁(monkey patch)
monkey patch指的是在运行时动态替换,一般是在startup的时候. 用过gevent就会知道,会在最开头的地方gevent.monkey.patch_all();把标准库中的thread/ ...
最新文章
- 不能解决,复选框在request对象获取的信息后显示在用户信息里面为中文的选项名...
- 机器学习知识点(二十五)Java实现隐马尔科夫模型HMM之jahmm库
- java 数组a赋值给数组b_java编程将a,b数组中不同的数字保存到一个新的数组中
- java file gettext_避免使用.properties文件GNU Gettext Java
- Java并发编程—自旋锁CLHLock原理
- spring cloud 总结
- PHP笔记-用户登录例子
- ShardingSphere(五) 公共表配置,实现读写改操作
- 深度优先搜索——全排列(洛谷 P1706)
- 越智能?越危险?技术到底应不应该进步?
- 网站访问量统计的重要指标
- python-爬取东方财富网期货市场大商所数据
- 【工控老马】力控7.0与S7-200SMART的驱动连接
- 【Flutter从入门到实战】⑩、Dart的Future和网络、Future-await-async、多核CPU-Isolate、网络请求、Dio的使用-二次封装
- 【《Unity 2018 Shaders and Effects Cookbook》翻译提炼】(九)Physically - Based Rendering
- artTemplate模板引擎
- 已知协方差矩阵求相关矩阵matlab,已知协方差矩阵求相关矩阵
- iOS UIButton 渐变色、边框渐变色、字体渐变色
- OpenCV 实现图片的水平投影与垂直投影,并进行行分割
- 搜索引擎只能抓取html文件,通过robots屏蔽搜索引擎抓取网站内容