Search code examples
pythonmonkeypatching

How does one monkey patch a function in python?


I'm having trouble replacing a function from a different module with another function and it's driving me crazy.

Let's say I have a module bar.py that looks like this:

from a_package.baz import do_something_expensive

def a_function():
    print do_something_expensive()

And I have another module that looks like this:

from bar import a_function
a_function()

from a_package.baz import do_something_expensive
do_something_expensive = lambda: 'Something really cheap.'
a_function()

import a_package.baz
a_package.baz.do_something_expensive = lambda: 'Something really cheap.'
a_function()

I would expect to get the results:

Something expensive!
Something really cheap.
Something really cheap.

But instead I get this:

Something expensive!
Something expensive!
Something expensive!

What am I doing wrong?


Solution

  • It may help to think of how Python namespaces work: they're essentially dictionaries. So when you do this:

    from a_package.baz import do_something_expensive
    do_something_expensive = lambda: 'Something really cheap.'
    

    think of it like this:

    do_something_expensive = a_package.baz['do_something_expensive']
    do_something_expensive = lambda: 'Something really cheap.'
    

    Hopefully you can realize why this doesn't work then :-) Once you import a name into a namespace, the value of the name in the namespace you imported from is irrelevant. You're only modifying the value of do_something_expensive in the local module's namespace, or in a_package.baz's namespace, above. But because bar imports do_something_expensive directly, rather than referencing it from the module namespace, you need to write to its namespace:

    import bar
    bar.do_something_expensive = lambda: 'Something really cheap.'