什么是猴贴?
你好,很高兴回答你的问题。猴子补丁的由来先讲我自己的笑话,说Python是我接触的第一门动态语言。用Python没多久就知道有个Gevent,学Gevent没多久就知道有个“猴子补丁”的概念。起初,我对这样一个名字感到非常高兴,猴子补丁。为什么叫这样的名字?是不是因为猴子反应快,敏感,Gevent也有这个特点,所以叫猴子补丁?然后这几天在看松本幸弘的《程序世界》这本书,里面有专门一章是讲猴子贴片的设计,我就笑了。原来猴子补丁不是我理解的,更不是Gevent开始做的。所谓猴子补丁,就是在不改变源代码的情况下,用动态语言添加和改变函数。猴子补丁的名字来源于Zope框架。当人们修复Zope bugs时,他们通常会在程序的后面添加更新。这些被称为“游击队”。后来游击逐渐写了gorllia(猩猩),后来又写了Monkey(猴子),所以猴子补丁这个名字就这么莫名其妙了。向Gevent学习monkey补丁的设计,充分利用动态语言的灵活性,可以对现有语言Api进行添加、替换、修改bug甚至性能优化。比如gevent的monkey补丁,可以增强和替代ssl、socket、os、time、select、thread、subprocess、sys等模块的功能。我们来看看gevent中的猴子补丁模块gevent.monkey的设计和实现。如果以后想自己设计实现猴子补丁,也可以按照这个模式来做。最近比较喜欢用ipython读python模块的代码。执行importgevent.monkey后,只需要输入?Gevent.monkey可以查看源代码。实际上,这个模块的核心只有几个功能。这些功能都位于模块之上。get_original、patch_item、remove_item和patch_module还有一个全局变量叫做saved,默认指向一个空的dictionary对象。首先来看一下patch_item函数的实现:defpatch _ item (module,attr,new item):None = object()ol ditem = get attr(module,attr,None) Ifolditemsnotnone: saved。Setdefault(模块。_ _ name _ _,{})。Setdefault (attr,olditem) Setattr (module,attr,newitem)该函数的作用是从指定的模块中查找旧项,将旧项保存在保存的字典中,然后用新项替换旧项。不使用None,而是构建一个空对象()作为默认属性。是NullPointer模式吗?然后是patch_module的实现:defpatch _ module (name,items = none):ge vent _ module = get attr(_ _ import _(' ge vent。'+name),name)module _ name = getattr (gevent _ module,' __target__ ',name)module = _ _ import _ _(module _ name)ifitemsonne:items = getattr(gevent _ module,__implements__ ',None)ifitemsonne:raiseattributeError(' % rdoesnothave _ _ implements _ _ ' % ge vent _ module)for attrinitems:patch _ item(module,Attr,getattr(ge vent _ module,Attr))gevent有一个约定,即ge vent模块作为比如gevent.socket就是socket模块的补丁。__implements__是要打补丁的属性,这是gevent.socket模块中__implements__的定义:# standardfunctionsandclasshathismodule-Implements inagevent-Aware方式:_ _ Implements _ =[' create _ connection ',' socket type ',' from FD ',' socket pair'] patch _ module的工作就是从gevent模块中读取这两个属性,然后遍历调用patch_item替换它们。但是有时候我们不想用打补丁的东西,而是用原来的模块来处理。我们做什么呢如前所述,当执行patch_item时,旧属性将保存在名为saved的全局字典中。如果您想要获取旧的模块属性,您应该调用get_original函数来从保存的字典中获取它们。in[6]:sleep = gevent . monkey . get _ original(" time "," sleep ")in[7]:sleep out[7]:in[8]:import time in[9]:time。sleep out [9]: monkey补丁很厉害,但也是特别针对gevent这样的补丁,直接替换API,整个Python过程中用到的模块都会被替换,自己的代码或许还能装。但在其他第三方库中,有时问题并不容易排查,即使查出来也很困难。所以就像松本建议的那样,如果要用猴子补丁,就只是添加功能,尽量避免大规模的API覆盖。希望能帮到你,请采纳。