Shankar
Shankar

Reputation: 3624

Python monkey patching objects not working as expected

I am trying to learn python monkey patching. I have a simple example where I am trying to monkey patch just a single instance rather than the class itself.

My code:

# add.py
import types


class Math(object):
    def __init__(self):
        self.name = ''

    def add(self, x, y, name):
        self.name = name
        print 'calling from ', self.name
        return x + y

    def monkey_patch(self):
        add = self.add

        def squared_sum(x, y):
            return x**2 + y**2
        add = types.MethodType(squared_sum, self)


if __name__ == '__main__':
    math = Math()
    print math.add(3, 4, 'before monkey_patching')
    math.monkey_patch()
    print math.add(3, 4, 'after monkey_patching')

Expected Output:

calling from  before monkey_patching
7
calling from  after monkey_patching
25

Generated Output:

calling from  before monkey_patching
7
calling from  after monkey_patching
7

Can someone point out where I am going wrong. And also how can I monkey patch the add method when I am doing it from a different file i.e. When I import Math class from add.py in a different file, how can I monkey patch it's add method.

Upvotes: 1

Views: 769

Answers (1)

jonrsharpe
jonrsharpe

Reputation: 122024

Your code doesn't do what you think it does:

def monkey_patch(self):
    add = self.add # add now points to self.add
    def squared_sum(x, y):
        return x**2 + y**2
    add = types.MethodType(squared_sum, self) # add now points to squared_sum
# method ends, add and squared_sum are abandoned

This doesn't actually change self.add. Also, squared_sum doesn't take self or name arguments, unlike add, and doesn't have the print that add does. To make this work fully, do:

def monkey_patch(self):
    def squared_sum(self, x, y, name):
        self.name = name
        print 'calling from ', self.name
        return x**2 + y**2
    self.add = types.MethodType(squared_sum, self) 

To patch outside the class definition:

math = Math()

def func(self, x, y, name):
    return x ** y

math.add = types.MethodType(func, math)

Upvotes: 4

Related Questions