import types
class A(object):#but seems to work for old style objects too
pass
def patch_me(target):
def method(target,x):
print "x=",x
print "called from", target
target.method = types.MethodType(method,target)
#add more if needed
a = A()
print a
#out: <__main__.A object at 0x2b73ac88bfd0>
patch_me(a) #patch instance
a.method(5)
#out: x= 5
#out: called from <__main__.A object at 0x2b73ac88bfd0>
patch_me(A)
A.method(6) #can patch class too
#out: x= 6
#out: called from <class '__main__.A'>
在Python中,函数和绑定方法是有区别的。
绑定方法已“绑定”(如何描述)到实例,并且每当调用该方法时,该实例将作为第一个参数传递。
但是,作为类(而不是实例)属性的可调用项仍然是未绑定的,因此您可以随时修改类定义:
以前定义的实例也会更新(只要它们没有重写属性本身):
如果要将方法附加到单个实例,则会出现问题:
当函数直接附加到实例时,它不会自动绑定:
要绑定它,我们可以使用MethodType function in the types module:
这次类的其他实例没有受到影响:
更多信息可以通过阅读descriptors和metaclassprogramming找到。
由于python 2.6和3.0中的删除,模块new不推荐使用,请使用类型
见http://docs.python.org/library/new.html
在下面的示例中,我故意从
patch_me()
函数中删除了返回值。 我认为给出返回值可能会让人认为patch返回了一个新对象,这不是真的-它修改了传入的对象。或许这可以促进更严格地使用monkeypatching。序言—关于兼容性的说明:其他答案可能只适用于Python2—这个答案在Python2和3中应该非常有效。如果只编写Python 3,则可以省略从
object
显式继承,否则代码应该保持不变。是的,这是可能的-但不推荐
我不推荐这个。这是个坏主意。别这么做。
有几个原因:
因此,我建议你不要这样做,除非你有一个很好的理由。最好在类定义中定义正确的方法,或者较少最好直接对类进行monkey修补,如下所示:
不过,既然这很有启发性,我就给你展示一些方法。
如何做到
这是一些设置代码。我们需要一个类定义。可以进口,但没关系。
创建实例:
创建要添加到其中的方法:
无方法(0)-使用描述符方法,
__get__
对函数的点式查找使用实例调用函数的
__get__
方法,将对象绑定到该方法,从而创建“绑定方法”现在:
方法1-类型。方法类型
首先,导入类型,我们将从中获取方法构造函数:
现在我们将该方法添加到实例中。为此,我们需要来自
types
模块(我们在上面导入)的MethodType构造函数。types.MethodType的参数签名是
(function, instance, class)
:使用方法:
方法二:词汇绑定
首先,我们创建一个包装函数,将方法绑定到实例:
用法:
方法三:functools.partial
部分函数将第一个参数应用于函数(以及可选的关键字参数),然后可以使用其余参数(以及重写关键字参数)调用。因此:
当您认为绑定方法是实例的部分函数时,这是有意义的。
将函数作为对象属性解除绑定-为什么这不起作用:
如果我们试图以与将sample_方法添加到类中相同的方式添加sample_方法,那么它将从实例中解除绑定,并且不会将隐式self作为第一个参数。
我们可以通过显式地传递实例(或者任何东西,因为这个方法实际上并不使用
self
参数变量)来使未绑定的函数工作,但是它与其他实例的预期签名不一致(如果我们正在对这个实例进行猴子修补):结论
你现在知道你可以用几种方法来做这件事,但严肃地说,不要这样做。
相关问题 更多 >
编程相关推荐