`
wx1568037608
  • 浏览: 33418 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

什么是猴子补丁

 
阅读更多

你好,很高兴为你解答。
猴子补丁的由来
首先说个我自己的笑话,话说Python算是我接触的稍微深点儿的第一门动态语言,用Python没多久就知道了有个Gevent,学习Gevent没多久就知道有个“猴子补丁”的概念。最开始觉得这么名字挺乐呵,猴子补丁,为啥叫这么个名儿?是因为猴子的动作迅速灵敏,Gevent也有这个特点,所以叫猴子补丁么?

然后这几天在看《松本行弘的程序世界》这本书,里面专门有一章讲了猴子补丁的设计,我就笑了,原来猴子补丁不是我理解的这个意思,更不是Gevent最开始这么做的。所谓的猴子补丁的含义是指在动态语言中,不去改变源码而对功能进行追加和变更。猴子补丁的这个叫法起源于Zope框架,大家在修正Zope的Bug的时候经常在程序后面追加更新部分,这些被称作是“杂牌军补丁(guerilla patch)”,后来guerilla就渐渐的写成了gorllia(猩猩),再后来就写了monkey(猴子),所以猴子补丁的叫法是这么莫名其妙的得来的。

从Gevent学习猴子补丁的设计
猴子补丁这种东西充分利用了动态语言的灵活性,可以对现有的语言Api进行追加,替换,修改Bug,甚至性能优化等等。比如gevent的猴子补丁就可以对ssl、socket、os、time、select、thread、subprocess、sys等模块的功能进行了增强和替换。我们来看下gevent中的猴子补丁模块gevent.monkey的设计和实现,以后如果自己要设计实现猴子补丁,也可以按照这么个模式去做,我最近比较喜欢用ipython来阅读python模块的代码,执行import gevent.monkey之后,只需要输入??gevent.monkey就可以查看源码了。

这个模块核心的函数其实就这几个,这些函数都位于模块的上方,get_original、patch_item、remove_item、patch_module还有一个全局变量叫做saved,默认指向一个空的字典对象。

首先来看patch_item函数的实现:

def patch_item(module, attr, newitem):
NONE = object()
olditem = getattr(module, attr, NONE)
if olditem is not NONE:
saved.setdefault(module.__name__, {}).setdefault(attr, olditem)
setattr(module, attr, newitem)
这个函数的功能就是从指定模块中查找旧的项,并把旧的项保存到saved字典中,然后将旧项替换成新项。

这里没有使用None,而是构建了一个空的object()作为默认属性,是NullPointer模式么?

然后是patch_module的实现:

def patch_module(name, items=None):
gevent_module = getattr(__import__('gevent.' + name), name)
module_name = getattr(gevent_module, '__target__', name)
module = __import__(module_name)
if items is None:
items = getattr(gevent_module, '__implements__', None)
if items is None:
raise AttributeError('%r does not have __implements__' % gevent_module)
for attr in items:
patch_item(module, attr, getattr(gevent_module, attr))

gevent有个约定,作为补丁的gevent模块要包含这两个属性,__target__和__implements__,__target__是被补丁的默认模块名称,可以不指定,默认为gevent子模块的名称,比如gevent.socket是socket模块的补丁,__implements__是要进行补丁的属性,这是gevent.socket模块中__implements__的定义:

# standard functions and classes that this module re-implements in a gevent-aware way:
__implements__ = ['create_connection',
'socket',
'SocketType',
'fromfd',
'socketpair']

patch_module的工作就是从gevent模块里面读取这两个属性,然后遍历调用patch_item进行替换。
可是有的时候我们不希望用补丁的东西,而是使用原先的模块去进行处理,该怎么办?前面提到过进行patch_item的时候会把旧的属性保存到名为saved的全局字典里面,如果要获得旧的模块属性,那么就要调用get_original函数从saved字典里面取出来。

In [6]: sleep = gevent.monkey.get_original("time", "sleep")
In [7]: sleep
Out[7]: <function time.sleep>
In [8]: import time
In [9]: time.sleep
Out[9]: <function gevent.hub.sleep>
猴子补丁
猴子补丁的功能很强大,但是也带来了很多的风险,尤其是像gevent这种直接进行API替换的补丁,整个Python进程所使用的模块都会被替换,可能自己的代码能hold住,但是其它第三方库,有时候问题并不好排查,即使排查出来也是很棘手,所以,就像松本建议的那样,如果要使用猴子补丁,那么只是做功能追加,尽量避免大规模的API覆盖。

分享到:
评论

相关推荐

    Python猴子补丁知识点总结

    Python中的猴子补丁(Monkey Patch)是一种在程序运行时修改现有模块、类或对象的行为,以便于调试、测试、优化或者扩展已有功能。这个术语来源于上述两种解释,无论是源自游击队员的灵活应变,还是源自猴子般随意...

    猴子补丁:将自定义javascript注入vscode

    猴子补丁自述文件 它有什么作用 Monkey Patch是一个扩展,允许在VSCode浏览器和主进程中执行任意JavaScript 它既可以直接通过配置选项使用,也可以由其他使用API​​的扩展使用。 通过更新后自动检查修补状态并...

    Monkey Patch猴子补丁编程方式及其在Ruby中的运用

    何谓猴子补丁(Monkey Patch)?在动态语言中,不修改源代码而对功能进行追加和变更。 使用猴子补丁的目的: 1、追加功能 2、功能变更 3、修正程序错误 4、增加钩子,在执行某个方法的同时执行一些其他的处理,...

    Python猴子补丁Monkey Patch用法实例解析

    为什么叫猴子补丁 属性的运行时替换和猴子也没什么关系,关于猴子补丁的由来网上查到两种说法: 1.这个词原来为Guerrilla Patch,杂牌军、游击队,说明这部分不是原装的,在英文里guerilla发音和gorllia(猩猩)相似,...

    python 猴子补丁(monkey patch)

    Python中的猴子补丁(Monkey Patching)是一种动态地修改或扩展已有类、模块或对象的行为的技术,无需修改其原始源代码。这种技术在Python中尤为常见,因为Python是动态类型的语言,允许在运行时对对象进行操作。...

    通过猴子补丁(monkey patch)动态修改 socket 的项目

    PySocket ,一个通过猴子补丁(monkey patch)动态修改 socket 的项目。在不修改源码的情况下给 socket 增加一些诸如限制客户端数量、前置代理之类的功能

    Ruby使用Monkey Patch猴子补丁方式进行程序开发的示例

    Monkey Patch,又称猴子补丁,是Ruby编程语言中一种独特的编程技术,允许程序员在程序运行时动态地修改或扩展已存在的类或模块。这一技术在Ruby社区中被广泛应用,尤其在处理第三方库的功能不足或者需要临时修复问题...

    dns-graceful-stack-switch:用于node.js的猴子补丁DNS查找方法

    用于node.js的猴子补丁DNS查找方法。 为什么? 如果您在禁用IPv4的情况下使用了node.js,则在大多数网络操作中都会出现异常(ENETUNREACH),但ping6 address正常工作。 要用最少的代码来解决此错误(您仍然可以...

    12.Gevent的猴子补丁.zip

    网络爬虫基础 网络爬虫的概述和原理 ...Python爬虫库的介绍 数据抓取与解析 ...JSON和XML数据的解析 动态网页爬取技术(如使用Selenium等) 反爬机制与应对策略 ...反爬机制的类型和常见手段 User-Agent设置和IP代理的应用 ...

    autowrapt:猴子补丁的Boostrap机制

    用于触发 Python 应用程序的猴子补丁的 Python 模块,无需实际修改 Python 应用程序本身来设置猴子补丁。 该包与wrapt模块一起工作。 可以根据wrapt模块要求创建导入后挂钩补丁模块,然后在安装了autowrapt模块的...

    Rearmed_rails:有用的Rails方法和猴子补丁的集合

    Rails的有用方法和猴子补丁的集合 该库与其他库的区别在于,所有猴子修补均以选择加入的方式执行,因为您不应该使用自己不知道的方法。 # Gemfile gem 'rearmed_rails' 运行rails g rearmed_rails:setup在config/...

    猴子版本通用补丁_123_

    ck竞技之王越南猴子通用版本h键......................

    node-monkeypatch:稍微简单的猴子补丁

    节点猴子补丁 稍微简单的猴子补丁。安装 npm install monkeypatch用法 monkeypatch ( target : Object , method : String , handler : Function ) : Function Monkeypatching 目标对象上的方法/函数会用新提供的处理...

    为什么要渲染:为什么要渲染猴子补丁React通知您可避免的重新渲染

    why-did-you-render猴子补丁React会通知您有关可避免的重新渲染。 (也可以与React Native一起使用。) 例如,如果您将style={{width: '100%'}}传递给一个大型的纯组件,它将在每次创建元素时始终重新渲染: 它...

    Rearmed-rb:Ruby中数组,哈希,可枚举,字符串,对象和日期的有用方法和猴子补丁的集合

    重装Ruby Ruby中用于数组,哈希,可枚举,字符串,对象和日期的有用方法和猴子补丁的集合。 通过使生活更轻松和编码更自然而受到驱动。 该库与其他库之间的区别在于,所有猴子修补均以选择加入的方式执行,因为您不...

    tmpdir.cr::monkey_face:猴子补丁,用于在Crystal标准库上创建tmp目录

    首先,我们需要理解“猴子补丁”是什么。猴子补丁是一种编程技术,允许程序员在运行时修改现有代码的行为,通常是库或框架的一部分。这种技术在动态语言中常见,但在静态类型如Crystal这样的语言中使用时需要更加...

Global site tag (gtag.js) - Google Analytics