Python:如何将 class 方法猴子补丁到其他 class 方法
Python: how to monkey patch class method to other class method
我得到了以下代码:
class A:
def __init__(self):
self.a = "This is mine, "
def testfunc(self, arg1):
print self.a + arg1
class B:
def __init__(self):
self.b = "I didn't think so"
self.oldtestfunc = A.testfunc
A.testfunc = self.testfuncPatch
def testfuncPatch(self, arg):
newarg = arg + self.b # B instance 'self'
self.oldtestfunc(self, newarg) # A instance 'self'
instA = A()
instB = B()
instA.testfunc("keep away! ")
我想执行以下操作:
一些 class A 由带参数的函数组成。
我想把这个函数修补成 class B 中的一个函数做一些操作参数和访问 class B 的变量,我的问题是修补函数实际上需要两个不同的 'self' 对象,即class A 的实例以及 class B.
的实例
这可能吗?
如果B
可以是A
的子类,问题就解决了
class B(A):
def __init__(self):
A.__init__(self)
# Otherwise the same
问题是,当您使用已绑定的方法重写 class 函数时,尝试绑定到其他实例时只会忽略第二个实例:
print(instA.testfunc)
#<bound method B.testfuncPatch of <__main__.B object at 0x1056ab6d8>>
所以该方法基本上被视为 staticmethod
,这意味着您必须将实例作为第一个参数来调用它:
instA.testfunc(instA,"keep away! ")
我在尝试将 random.shuffle
直接导入 class 以使其成为方法时首先 运行 解决了这个问题:
class List(list):
from random import shuffle #I was quite surprised when this didn't work at all
a = List([1,2,3])
print(a.shuffle)
#<bound method Random.shuffle of <random.Random object at 0x1020c8c18>>
a.shuffle()
Traceback (most recent call last):
File "/Users/Tadhg/Documents/codes/test.py", line 5, in <module>
a.shuffle()
TypeError: shuffle() missing 1 required positional argument: 'x'
为了解决这个问题,我创建了一个可以在第一个实例之上反弹到第二个实例的函数:
from types import MethodType
def rebinder(f):
if not isinstance(f,MethodType):
raise TypeError("rebinder was intended for rebinding methods")
def wrapper(*args,**kw):
return f(*args,**kw)
return wrapper
class List(list):
from random import shuffle
shuffle = rebinder(shuffle) #now it does work :D
a = List(range(10))
print(a.shuffle)
a.shuffle()
print(a)
#output:
<bound method rebinder.<locals>.wrapper of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>
[5, 6, 8, 2, 4, 1, 9, 3, 7, 0]
因此您可以轻松地将其应用到您的情况中:
from types import MethodType
def rebinder(f):
if not isinstance(f,MethodType):
raise TypeError("rebinder was intended for rebinding methods")
def wrapper(*args,**kw):
return f(*args,**kw)
return wrapper
...
class B:
def __init__(self):
self.b = "I didn't think so"
self.oldtestfunc = A.testfunc
A.testfunc = rebinder(self.testfuncPatch) #!! Edit here
def testfuncPatch(selfB, selfA, arg): #take the instance of B first then the instance of A
newarg = arg + selfB.b
self.oldtestfunc(selfA, newarg)
我得到了以下代码:
class A:
def __init__(self):
self.a = "This is mine, "
def testfunc(self, arg1):
print self.a + arg1
class B:
def __init__(self):
self.b = "I didn't think so"
self.oldtestfunc = A.testfunc
A.testfunc = self.testfuncPatch
def testfuncPatch(self, arg):
newarg = arg + self.b # B instance 'self'
self.oldtestfunc(self, newarg) # A instance 'self'
instA = A()
instB = B()
instA.testfunc("keep away! ")
我想执行以下操作:
一些 class A 由带参数的函数组成。 我想把这个函数修补成 class B 中的一个函数做一些操作参数和访问 class B 的变量,我的问题是修补函数实际上需要两个不同的 'self' 对象,即class A 的实例以及 class B.
的实例这可能吗?
如果B
可以是A
的子类,问题就解决了
class B(A):
def __init__(self):
A.__init__(self)
# Otherwise the same
问题是,当您使用已绑定的方法重写 class 函数时,尝试绑定到其他实例时只会忽略第二个实例:
print(instA.testfunc)
#<bound method B.testfuncPatch of <__main__.B object at 0x1056ab6d8>>
所以该方法基本上被视为 staticmethod
,这意味着您必须将实例作为第一个参数来调用它:
instA.testfunc(instA,"keep away! ")
我在尝试将 random.shuffle
直接导入 class 以使其成为方法时首先 运行 解决了这个问题:
class List(list):
from random import shuffle #I was quite surprised when this didn't work at all
a = List([1,2,3])
print(a.shuffle)
#<bound method Random.shuffle of <random.Random object at 0x1020c8c18>>
a.shuffle()
Traceback (most recent call last):
File "/Users/Tadhg/Documents/codes/test.py", line 5, in <module>
a.shuffle()
TypeError: shuffle() missing 1 required positional argument: 'x'
为了解决这个问题,我创建了一个可以在第一个实例之上反弹到第二个实例的函数:
from types import MethodType
def rebinder(f):
if not isinstance(f,MethodType):
raise TypeError("rebinder was intended for rebinding methods")
def wrapper(*args,**kw):
return f(*args,**kw)
return wrapper
class List(list):
from random import shuffle
shuffle = rebinder(shuffle) #now it does work :D
a = List(range(10))
print(a.shuffle)
a.shuffle()
print(a)
#output:
<bound method rebinder.<locals>.wrapper of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>
[5, 6, 8, 2, 4, 1, 9, 3, 7, 0]
因此您可以轻松地将其应用到您的情况中:
from types import MethodType
def rebinder(f):
if not isinstance(f,MethodType):
raise TypeError("rebinder was intended for rebinding methods")
def wrapper(*args,**kw):
return f(*args,**kw)
return wrapper
...
class B:
def __init__(self):
self.b = "I didn't think so"
self.oldtestfunc = A.testfunc
A.testfunc = rebinder(self.testfuncPatch) #!! Edit here
def testfuncPatch(selfB, selfA, arg): #take the instance of B first then the instance of A
newarg = arg + selfB.b
self.oldtestfunc(selfA, newarg)