Suppose I have a class Foobar and I want to redefine a method of one of its instances:

class Foobar:
    def myMethod(self):
        print('this method was not overridden')

foo = Foobar()

def foo.myMethod:
    print('this method was overridden')

Problem is, this approach throws errors. Is there a way to redefine object methods?


Solution 1:

You can just create a new method and assign it

def new_method():
    print("Hello")

foo.myMethod = new_method

Solution 2:

What you are trying to do is called monkeypatching.

Methods are non-data descriptors, which means that anything you put in the instance __dict__ with the same name will override it:

class Foobar:
    def myMethod(self):
        print('this method was not overridden')

foo = Foobar()

type(foo.myMethod) shows method.

def myMethod():
    print('this method was overridden')

foo.myMethod = myMethod

Now type(foo.myMethod) shows function.

Since you access foo.myMethod() from foo.__dict__, you won't be able to invoke the descriptor protocol. In other words, you won't be able to pass self to myMethod.

To fully replace the method, invoke the descriptor protocol manually, and create a bound method object:

def myMethod(self):
    print('this method was overridden')

foo.myMethod = myMethod.__get__(foo)

Now type(foo.myMethod) shows method again. This is important because if you wanted to monkey-patch the class, you could do it with the full version and have it work out of the box:

Foo.myMethod = myMethod

The first version would raise an error if you tried calling foo.myMethod, while the second would work as expected.