So the tricky thing here is that what you get depends on where the method lives:
class A(object):
def foo(self):
print("Hello world")
def patch(self):
print("patched!")
print(type(A.foo))
a = A()
print(type(a.foo))
If you run this, you'll get different results on python2.x and 3.x:
$ python ~/sandbox/test.py # python2.x
<type 'instancemethod'>
<type 'instancemethod'>
$ python3 ~/sandbox/test.py # python3.x
<class 'function' at 0x100228020>
<class 'method' at 0x10021d0c0>
But in either case it's clear that a.foo
is a method of some sort.
What happens if we try to monkey patch it?
a.foo = patch
print(type(a.foo)) # <type 'function'> (2.x) / <class 'function'> (3.x)
Ok, now we see that a.foo
is of type function
(not a method). So the question is how do we make a method out of out "patch"? The answer is we use it's descriptor protocol when adding it as an attribute:
a.foo = patch.__get__(a, A)
For a method on a class, when you do a.some_method
, python actually does: a.some_method.__get__(a, type(a))
so we're just reproducing that call sequence here (explicitly).