python的猴子补丁(Monkey Patching)

1. 什么是猴子补丁

Python是一种典型的动态脚本语言。它不仅具有 动态类型(dynamic type) ,而且它的 对象模型(object model) 也是动态的。Python的类是可变的(mutable),方法(methods)只是类的属性(attributes);这允许我们在 运行时(run time) 修改其行为。这被称为猴子补丁(Monkey Patching), 它指的是偷偷地更改代码。

Monkey Patching只是在 运行时(run time) 动态替换属性(attributes)。 而在Python中,术语monkey patch指的是对函数(function)、类(class)或模块(module)的动态(或运行时)修改。

2. 举例说明

假设在monkey.py文件中已经定义了一个类:

# monkey.py
class Me:def who_am_i(self):print("I am a Monkey")

假设monkey.py文件中的Me这个类不是我写的,我只是用到了这个类 为了演示的方便,这个类只有一个who_am_i() 方法,作用是打印"I am a Monkey"
现在我在另外一个文件中想要调用这个类,但是发现这个类里面的who_am_i() 方法不是我想要的内容。

由于我是一个人类,我不喜欢打印我是一个猴子,我想要打印 “I am human”,
所以我给猴子对象打补丁(这里是一个双关语,就是monkey patch的名字的来源),我们可以这么实现:

import monkey  # 导入用到的别人写的monkey模块def i_am_human(self):  # 定义一个我们想要的方法print("I am human")print(f"{monkey.Me.who_am_i = }")  # 替换前,将原来的方法地址打印出来
monkey.Me.who_am_i = i_am_human  # 将"who_am_i"的地址替换为"i_am_human"
print(f"{monkey.Me.who_am_i = }")  # 替换后,将原来的方法地址打印出来
​
obj = monkey.Me()  # 实例化一个对象print(f"{hasattr(obj, 'i_am_human') = }")
print(f"{hasattr(obj, 'who_am_i') = }")
obj.who_am_i()  # 直接调用 "who_am_i" 而不是 "i_am_human()"

输出的结果:

monkey.Me.who_am_i = <function Me.who_am_i at 0x7ff6ab1d9af0>
monkey.Me.who_am_i = <function i_am_human at 0x7ff6ab2a0310>
hasattr(obj, 'i_am_human') = False
hasattr(obj, 'who_am_i') = True
I am human

这个例子的结论:

1.我们可以自己定义一个新的方法(或者函数)来更改掉原来类的方法
2.替换以后,原来类的方法名称还在,但是它的内存地址已经发生变化了
3.调用的时候,只能使用原来的方法名来调用,而不是新的方法名称
4.新的方法名称只是包含了实现过程,对于类本身,是看不到这个方法名称的。

3. 其他对象使用猴子补丁

3.1. 使用猴子补丁修复类的实例

上面使用了猴子补丁来修复了一个类的方法, 那么该类的所有实例使用该方法的时候都将使用的是修补后的方法。

如果我们想要减少影响,只修补特定的实例对象, 可是可以完成的,代码如下:

import types
import monkey  # 导入用到的别人写的monkey模块
​
monkey1 = monkey.Me()
monkey2 = monkey.Me()def i_am_human(self):print("I am human")
​
monkey2.who_am_i = types.MethodType(i_am_human, monkey2)
monkey1.who_am_i()
monkey2.who_am_i()

输出的结果:

I am a Monkey
I am human

这个例子的结论:

同一个类的两个实例中,我们可以单独给某一个实例打猴子补丁,而完全不影响另外一个实例.

3.2. 其他对象使用猴子补丁

我们还可以对其他的对象使用猴子补丁,比如模块等, 这里有一个比较实用的例子:

比如你的一个项目中,很多python文件中都用到了import json,后来发现如果使用ujson性能会更高, 但是觉得把每个文件的 import json 都改成 import ujson as json 成本较高(不要光想着替换,很多项目不仅仅有你一个开发人员); 或者仅仅想测试一下用ujson替换json是否符合预期。
对于这种需求,只需要在程序的主入口处加上下面的代码:

import json  
import ujson  
​
def monkey_patch_json():  json.__name__ = 'ujson'  json.dumps = ujson.dumps  json.loads = ujson.loads  
​
monkey_patch_json()

这样后面:

  • 所有用到json.dumps就会自动调用ujson.dumps
  • 所有用到json.loads就会自动调用ujson.loads

4. 使用场景与注意事情

可以看到猴子修补非常强大,几乎可以在任何地方修改原来类的实现或者对象的原有功能。但是恰恰是由于其可以随时随地修改,会造成某个对象的具体功能是在哪儿实现的这点非常不明确(破环封装),这会严重影响程序的鲁棒性,容易引发不必要的Bug。 所以要慎用!

猴子补丁合适的使用场景:

  1. 我们正在处理来自其他人的写的公共代码,优化了一个小的实现,我们目前不想对其源码进行修改(因为其他人还有可能在用这些代码,或者其他版本中有可能用到),我可以将这个补丁放在自己的代码中,即保证了功能的实现,也不影响别人实现
  2. 我们正在处理来自其他人的遗留代码或代码,我们不想对其进行广泛修改,但仍然希望使其与不同版本的库或环境一起运行,这非常有用。

因此,对于猴子补丁,我个人建议:

  • 如果代码的影响范围可控,不要使用猴子补丁,直接更改原来方法的实现
  • 如果要使用猴子补丁,尽量在最终端的类或者实例中,不要在中间类中使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/614555.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

助力智能密集人群检测计数,基于YOLOv8全系列模型【n/s/m/l/x】开发构建通用场景下密集人群检测计数识别系统

在一些人流量比较大的场合&#xff0c;或者是一些特殊时刻、时段、节假日等特殊时期下&#xff0c;密切关注当前系统所承载的人流量是十分必要的&#xff0c;对于超出系统负荷容量的情况做到及时预警对于管理团队来说是保障人员安全的重要手段&#xff0c;本文的主要目的是想要…

php物联网平台云监控WEB设备iot管理后台源码带文字安装教程

物联网平台云监控WEB设备iot管理后台源码带文字安装教程 运行环境 服务器宝塔面板 PHP 5.6 Mysql 5.6 Linux Centos7以上 物联网监控平台&#xff0c;含有web平台、APP代码、硬件短代码&#xff0c;可使用Wifi、2G、4G硬件模块。 具有数据查看、集中显示、报警功能&#xff0c;…

FPGA图形化前仿真

引言 上文提到电路连接如下&#xff1a; 期望结果如下&#xff1a; 一.创建wrapper文件 1.创建HDL wrapper&#xff1b; 2.要是该文件不是顶层&#xff08;set as top&#xff09;&#xff0c;则需要把文件置于顶层 二.综合 1.综合的目的主要是排除语法的错误&#xff1b; 2.内…

重磅!GPT Store正式上线!

GPT Store来了。根据公告&#xff0c;用户可以在ChatGPT Plus、Team和Enterprise中访问、分享和销售使用OpenAI技术创建的AI模型。 而且&#xff0c;GPT Store确实有“推荐”机制&#xff1a;“特色GPTs”&#xff0c;商店会每周更新一批官方推荐的GPTs。另外OpenAI提供了“举报…

【sqlite3】sqlite3在linux下使用sqlitebrowser工具实现数据可视化

sqlite3在linux下使用sqlitebrowser工具实现数据可视化 1. ### install sqlitebrowser 1. ### install sqlitebrowser 安装指令 sudo apt-get install sqlitebrowser通过工具打开数据库 sqlitebrowser stereo.db打开效果

1.6计算机网络的性能指标

1.6计算机网络的性能指标 常用的计算机网络的性能指标有7个&#xff1a;速率、带宽、吞吐量、时延、往返时间、利用率、丢包率 1.6.1速率 计算机发送的信号是以二进制数字形式的。一个二进制数字就是一个比特(bit&#xff0c;binary digit)字节:Byte&#xff0c;1Byte8bit(1…

数据结构(三)堆和哈希表

目录 哈希表和堆什么是哈希表 &#xff1f;什么是堆 &#xff1f;什么是图 &#xff1f;案例一&#xff1a;使用python实现最小堆案例二 &#xff1a; 如何用Python通过哈希表的方式完成商品库存管理闯关题 &#xff08;包含案例三&#xff1a;python实现哈希表&#xff09; 本…

强化学习求解TSP(八):Qlearning求解旅行商问题TSP(提供Python代码)

一、Qlearning简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于奖励的决策问题。它是一种无模型的学习方法&#xff0c;通过与环境的交互来学习最优策略。Q-learning的核心思想是通过学习一个Q值函数来指导决策&#xff0c;该函数表示在给定状态下采取某个动作所获…

MySQL修炼手册4:分组与聚合:GROUP BY与HAVING的应用

写在开头 MySQL数据库的强大功能为我们提供了丰富的数据处理工具&#xff0c;其中GROUP BY与HAVING的应用使得数据的分组与聚合变得更加灵活和高效。在本篇博客中&#xff0c;我们将深入研究GROUP BY与HAVING的基础知识&#xff0c;并通过实际案例&#xff0c;展示它们在数据分…

vue的mvvm模式

1.mvvm优点&#xff1a; 低耦合&#xff1a;视图&#xff08;View&#xff09;可以独立于Model变化和修改&#xff0c;一个ViewModel可以绑定到不同的View上&#xff0c;当View变化的时候Model可以不变&#xff0c;当Model变化的时候&#xff0c;View也可以不变。 可复用&…

使用ros_arduino_bridge控制机器人底盘

使用ros_arduino_bridge控制机器人底盘 搭建了ROS分布式环境后,将ros_arduino_bridge功能包上传至Jetson nano&#xff0c;就可以在PC端通过键盘控制小车的运动了。实现流程如下&#xff1a; 系统准备&#xff1b;下载程序&#xff1b;程序修改&#xff1b;分别启动PC与Jetson…

基于嵌入式的智能台灯系统

基于嵌入式的智能台灯系统 功能说明 通过微信小程序控制台灯的亮灭及亮度。采集温湿度传到微信小程序上&#xff0c;台灯可以显示实时北京时间。 功能展示 01智能台灯演示 Mqtt服务器 http://www.yoyolife.fun/iot&#xff1a;Mqtt服务器&#xff0c;我是在这里注册的&#x…

ubuntu20固定串口名称

查看串口的详细信息 udevadm info --name/dev/ttyUSB0结果&#xff1a; P: /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.2/1-1.2:1.0/ttyUSB0/tty/ttyUSB0 N: ttyUSB0 L: 0 S: serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UAR…

电阻如何读取阻值

前言&#xff1a;大家经常见到的贴片电阻上的丝印有纯数字、数字与R组合、数字与除R之外的字母组合的&#xff0c;但大家知不知道这样的标注与贴片电阻的i精度相关&#xff1f;同一个阻值因为精度不同&#xff0c;标注也会不同。例如封装为0805的贴片电阻&#xff0c;丝印473和…

小程序的完整开发流程?

小程序的完整开发流程可以分为以下几个步骤&#xff1a; 需求分析和设计&#xff1a;明确小程序的功能需求和设计思路&#xff0c;包括页面结构、交互逻辑等。 环境搭建&#xff1a;安装并配置开发工具&#xff0c;如微信开发者工具或其他小程序开发工具。 项目初始化&#x…

【机器学习】模型保存

一、模型建立 from sklearn import svm from sklearn import datasetsclf svm.SVC() iris datasets.load_iris() X, y iris.data, iris.target clf.fit(X, y) 二、保存法1&#xff1a;pickle 保存模型 import pickle with open(../save/clf.pickle, wb) as f:pickle.dum…

tailwindcss真的好用吗?

写在前面 今天写一篇关于tailwindcss 的文章&#xff0c;其实这个css技术已经出现很久了&#xff0c;在一些大型项目很多人也已经在用了&#xff0c;虽然不是说必须要会吧&#xff0c;但是没听说过肯定是不行的&#xff0c;他的操作逻辑应该是和unocss差不多&#xff0c;但是今…

Docker 安装:在linux系统CentOS7 版本 安装Docker

目录 一&#xff0c;Docker介绍&#xff1a; 1.1Docker是什么&#xff1f; 1.2Docker组成 二&#xff0c;Docker安装&#xff1a; 三&#xff0c;Docker基本使用 3.1服务 3.2镜像 3.3容器 &#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&am…

数据库系统原理总结之——数据库编程

第五章 数据库编程 第五章 数据库编程一、存储过程 ★★★ 1. 好处2. 创建3. 存储过程体a.局部变量b.游标3. 调用4. 删除二、存储函数和存储过程的区别 ★★★ 1. 存储函数2. 存储过程第五章 数据库编程 一、存储过程

java SSM物业管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM物业管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和 数据库&#xff0c;系统主要采用B/…