《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)相关推荐

  1. python的猴子补丁(Monkey Patching)

    0. 参考文档 参考文档如下: https://achowdhary.com/monkey-patching/ https://www.cnblogs.com/xp1315458571/p/16049 ...

  2. 猴子补丁 - Monkey Patching

    0 猴子补丁 - Monkey Patching 1 定义, 2 猴子补丁(monkey patching) 3 在运行时动态修改模块.类或函数,通常是添加功能或修正缺陷.猴子补丁在代码运行时 4 ( ...

  3. 猴子补丁(Monkey Patching)

    猴子补丁是我在面试的时候接触的一到题,学python的时候,我根本就没有听说这个概念!那接下来我们来分析一下: 1.什么是猴子补丁? 2.猴子补丁的功能? 3.猴子补丁的应用场景? 一.什么是猴子补丁 ...

  4. python画猴子_Python猴子补丁Monkey Patch用法实例解析

    属性在运行时的动态替换,叫做猴子补丁(Monkey Patch). 为什么叫猴子补丁 属性的运行时替换和猴子也没什么关系,关于猴子补丁的由来网上查到两种说法: 1.这个词原来为Guerrilla Pa ...

  5. python猴子补丁_Python猴子补丁Monkey Patch用法实例解析

    属性在运行时的动态替换,叫做猴子补丁(Monkey Patch). 为什么叫猴子补丁 属性的运行时替换和猴子也没什么关系,关于猴子补丁的由来网上查到两种说法: 1.这个词原来为Guerrilla Pa ...

  6. python设计模式之猴子补丁模式

    1.所有书中都没有把猴子补丁作为一种设计模式来看待.因为设计模式的模式的命名是根据java中提炼出来的,语言方式决定了java绝对不会有也不需要有这种操作,不存在的.那自然设计模式不会包括猴子补丁模式 ...

  7. 【华为云技术分享】python教程:猴子补丁

    猴子补丁指在运行时修改类或者模块,而不是改动定义类或者模块的源代码. 假设有预先定义的类A: class Apple:def __init__(self):self._color = 'red'def ...

  8. python中模块打补丁

    前言:今天接触到一个常听的名词也感觉很深奥的词语,补丁,有点好奇就来研究研究 假定现在有模块一和模块二,想调用模块二中的一个方法,但是不小心写成了模块一中的方法,在不大浮动 改动主程序代码的前提下,通 ...

  9. 什么是猴子补丁(monkey patch)

    monkey patch指的是在运行时动态替换,一般是在startup的时候. 用过gevent就会知道,会在最开头的地方gevent.monkey.patch_all();把标准库中的thread/ ...

最新文章

  1. 不能解决,复选框在request对象获取的信息后显示在用户信息里面为中文的选项名...
  2. 机器学习知识点(二十五)Java实现隐马尔科夫模型HMM之jahmm库
  3. java 数组a赋值给数组b_java编程将a,b数组中不同的数字保存到一个新的数组中
  4. java file gettext_避免使用.properties文件GNU Gettext Java
  5. Java并发编程—自旋锁CLHLock原理
  6. spring cloud 总结
  7. PHP笔记-用户登录例子
  8. ShardingSphere(五) 公共表配置,实现读写改操作
  9. 深度优先搜索——全排列(洛谷 P1706)
  10. 越智能?越危险?技术到底应不应该进步?
  11. 网站访问量统计的重要指标
  12. python-爬取东方财富网期货市场大商所数据
  13. 【工控老马】力控7.0与S7-200SMART的驱动连接
  14. 【Flutter从入门到实战】⑩、Dart的Future和网络、Future-await-async、多核CPU-Isolate、网络请求、Dio的使用-二次封装
  15. 【《Unity 2018 Shaders and Effects Cookbook》翻译提炼】(九)Physically - Based Rendering
  16. artTemplate模板引擎
  17. 已知协方差矩阵求相关矩阵matlab,已知协方差矩阵求相关矩阵
  18. iOS UIButton 渐变色、边框渐变色、字体渐变色
  19. OpenCV 实现图片的水平投影与垂直投影,并进行行分割
  20. 搜索引擎只能抓取html文件,通过robots屏蔽搜索引擎抓取网站内容

热门文章

  1. python week 获取 星期 第几周 开始日期 结束日期 星期几
  2. 第三方网站登录微信——保姆级
  3. Office 修复、卸载重装方法
  4. 深入浅出,一篇超棒的机器学习入门文章
  5. 【单片机】Android手机USB外接STM32单片机通过ADB实现投屏反向控制的功能
  6. SAP 凭证跳号分析
  7. 信息隐藏与数字水印实验:图片类隐写(MATLAB)
  8. 微信:签名不对,请检查签名是否与开放平台上填写的一致
  9. 正则校验字符串中汉字数量及总数量
  10. TIMESAT 无格式文件迭代转tif