Python 什么是猴子修补术?
我试图理解,什么是猴子补丁或猴子补丁 这是否类似于方法/运算符重载或委派 它与这些东西有什么共同之处吗?根据: 在Python中,术语monkey patch仅用于 指的是对对象的动态修改 运行时的类或模块,受激励 通过修补现有的 第三方代码作为解决方案 不起作用的bug或特性 你想要的Python 什么是猴子修补术?,python,terminology,monkeypatching,Python,Terminology,Monkeypatching,我试图理解,什么是猴子补丁或猴子补丁 这是否类似于方法/运算符重载或委派 它与这些东西有什么共同之处吗?根据: 在Python中,术语monkey patch仅用于 指的是对对象的动态修改 运行时的类或模块,受激励 通过修补现有的 第三方代码作为解决方案 不起作用的bug或特性 你想要的 不,它不像那些东西。它只是在运行时动态替换属性 例如,考虑一个类,该类具有一个方法:代码> GETyDATA < /COD>。此方法执行外部查找(例如,在数据库或web API上),类中的其他各种方法调用它。但
不,它不像那些东西。它只是在运行时动态替换属性
例如,考虑一个类,该类具有一个方法:代码> GETyDATA < /COD>。此方法执行外部查找(例如,在数据库或web API上),类中的其他各种方法调用它。但是,在单元测试中,您不希望依赖于外部数据源,因此可以使用返回一些固定数据的存根动态替换
get\u data
方法
因为Python类是可变的,而方法只是类的属性,所以您可以随心所欲地执行此操作——事实上,您甚至可以用完全相同的方式替换模块中的类和函数
但是,正如一位专家所指出的,在修补monkeypatching时要小心:
get_data
,那么它也会调用您的monkey patched replacement,而不是原始的,这可能是好的,也可能是坏的。小心点get_data
函数的变量或属性,则此别名不会改变其含义,并将继续指向原始get_data
。(为什么?Python只是将类中的名称get_data
重新绑定到其他函数对象;其他名称绑定根本不受影响。)第一:猴子补丁是一种邪恶的黑客(在我看来) 它通常用于用自定义实现替换模块或类级别的方法
最常见的用例是在无法替换原始代码时,为模块或类中的错误添加一个变通方法。在这种情况下,您可以使用自己的模块/包中的实现通过monkey patching替换“错误”的代码。monkey patching只能在动态语言中完成,python就是一个很好的例子。例如,在运行时更改方法而不是更新对象定义;类似地,在运行时添加属性(无论是方法还是变量)被认为是猴子补丁。这些通常是在使用没有源代码的模块时完成的,因此对象定义不容易更改 这被认为是不好的,因为这意味着对象的定义不能完全或准确地描述其实际行为 MonkeyPatch是一段Python代码,可以扩展或修改 运行时的其他代码(通常在启动时) 一个简单的例子如下所示:
from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
return "ook ook eee eee eee!"
SomeClass.speak = speak
来源:Zope wiki上的页面
什么是猴子补丁?
简单地说,monkey patching就是在程序运行时对模块或类进行更改
使用中的示例
熊猫文档中有一个猴子修补的例子:
import pandas as pd
def just_foo_cols(self):
"""Get a list of column names containing the string 'foo'
"""
return [x for x in self.columns if 'foo' in x]
pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method
要解决此问题,首先我们导入模块:
import pandas as pd
接下来,我们创建一个方法定义,它存在于任何类定义的范围之外(因为函数和未绑定方法之间的区别是毫无意义的,Python 3取消了未绑定方法):
接下来,我们只需将该方法附加到要在其上使用的类:
pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
然后我们可以在类的实例上使用该方法,并在完成后删除该方法:
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method
名称损坏的警告
如果您使用名称mangling(在属性前面加上双下划线,这会改变名称,我不推荐这样做),如果您这样做,您必须手动命名mangle。因为我不推荐名称损坏,所以我不会在这里演示
测试示例
例如,我们如何在测试中使用这些知识
假设我们需要模拟对外部数据源的数据检索调用,从而导致错误,因为我们希望在这种情况下确保行为正确。我们可以对数据结构进行修补以确保这种行为。(因此使用Daniel Roseman建议的类似方法名称:)
当我们测试依赖于此方法的行为时,会引发错误,如果正确实现,我们将在测试结果中得到该行为
仅执行上述操作将改变进程生命周期内的结构
对象,因此您希望在单元测试中使用设置和拆卸来避免这样做,例如:
def setUp(self):
# retain a pointer to the actual real method:
self.real_get_data = datasource.Structure.get_data
# monkey patch it:
datasource.Structure.get_data = get_data
def tearDown(self):
# give the real method back to the Structure object:
datasource.Structure.get_data = self.real_get_data
(虽然上面的操作很好,但是使用
mock
库来修补代码可能是一个更好的主意。mock
的patch
decorator比上面的操作更不容易出错,这将需要更多的代码行,从而有更多的机会引入错误。我还没有在mock但我想它也以类似的方式使用monkey patching。)monkey patching是在运行时重新打开类中现有的类或方法,并更改行为,应该谨慎使用,或者只在真正需要时才使用
由于Python是一种动态编程语言,类是可变的,因此您可以重新打开它们,修改甚至替换它们
什么是monkey patching?monkey patching是一种用于在运行时动态更新代码行为的技术
为什么要使用猴子补丁?它允许我们在运行时修改或扩展库、模块、类或方法的行为,而无需
实际修改源代码
结论猴子修补术是一种很酷的技术,现在我们已经学会了如何进行修补
import datasource
def get_data(self):
'''monkey patch datasource.Structure with this to simulate error'''
raise datasource.DataRetrievalError
datasource.Structure.get_data = get_data
def setUp(self):
# retain a pointer to the actual real method:
self.real_get_data = datasource.Structure.get_data
# monkey patch it:
datasource.Structure.get_data = get_data
def tearDown(self):
# give the real method back to the Structure object:
datasource.Structure.get_data = self.real_get_data