проблема в том, что, когда вы переопределить функцию класса с уже связанным методом, пытаясь связать с другими экземплярами просто игнорировать второй экземпляр:
print(instA.testfunc)
#<bound method B.testfuncPatch of <__main__.B object at 0x1056ab6d8>>
поэтому метод в основном трактуется как staticmethod
означает, что вы должны были бы назвать его с экземпляром в качестве первого аргумента:
instA.testfunc(instA,"keep away! ")
я первый столкнулся с этой проблемой при попытке импортировать random.shuffle
непосредственно в класс, чтобы сделать его метод:
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)
Спасибо за ваш вклад, я хочу сделать это без B является подклассом, так как я только хочу, чтобы обезьяна патч этот единственный метод и B не должен делать что-нибудь рег кроме того. Мне, вероятно, нужно обезвредить несколько методов, таких как testfunc из других классов внутри B в моем проекте, что приведет к той же проблеме ...: S –