826

I am trying to understand, what is monkey patching or a monkey patch?

Is that something like methods/operators overloading or delegating?

Does it have anything common with these things?

Lutz Prechelt
  • 36,608
  • 11
  • 63
  • 88
Sergei Basharov
  • 51,276
  • 73
  • 200
  • 335
  • 31
    I think the definition from google is useful and most general: `Monkey patching is a technique to add, modify, or suppress the default behavior of a piece of code at runtime without changing its original source code.` – Charlie Parker Jun 09 '20 at 19:43

8 Answers8

744

No, it's not like any of those things. It's simply the dynamic replacement of attributes at runtime.

For instance, consider a class that has a method get_data. This method does an external lookup (on a database or web API, for example), and various other methods in the class call it. However, in a unit test, you don't want to depend on the external data source - so you dynamically replace the get_data method with a stub that returns some fixed data.

Because Python classes are mutable, and methods are just attributes of the class, you can do this as much as you like - and, in fact, you can even replace classes and functions in a module in exactly the same way.

But, as a commenter pointed out, use caution when monkeypatching:

  1. If anything else besides your test logic calls get_data as well, it will also call your monkey-patched replacement rather than the original -- which can be good or bad. Just beware.

  2. If some variable or attribute exists that also points to the get_data function by the time you replace it, this alias will not change its meaning and will continue to point to the original get_data. (Why? Python just rebinds the name get_data in your class to some other function object; other name bindings are not impacted at all.)

Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • 2
    @LutzPrechelt just to be clear for me, what do you mean with `pointing to the original get_data function`? Do you mean when you stores a function inside a variable if someone changes that function the variable will continue pointing to the old one? – fabriciorissetto Nov 13 '17 at 16:45
  • 12
    @fabriciorissetto: You don't normally change function objects in Python. When you monkey-patch `get_data`, you rebind the name `get_data` to a mock function. If some other name somewhere else in the program is bound to the-function-formerly-known-as-`get_data`, nothing will change for that other name. – Lutz Prechelt Nov 14 '17 at 14:34
  • I think monkey patching can be useful especially for debugging, and in decorators or object factories functions. However, remember explicit is better than implicit so make sure that your code is context-insensitive, read "Goto considered harmful", etc... – aoeu256 Sep 09 '19 at 16:35
  • So, it is just something akin to using ‘eval’ function, where you could insert new code at runtime? – wintermute Feb 23 '20 at 14:21
  • your definition seems way to simple. The definition from google `Monkey patching is a technique to add, modify, or suppress the default behavior of a piece of code at runtime without changing its original source code.` sounds a lot more flexible "only reassigning attributes". I can imagine a piece of code that returns random numbers, then monkey patching it by always increasing the numbers given by 2 by wrapping the original in a new function and that didn't require any classes or anything. – Charlie Parker Jun 09 '20 at 19:42
453

A MonkeyPatch is a piece of Python code which extends or modifies other code at runtime (typically at startup).

A simple example looks like this:

from SomeOtherProduct.SomeModule import SomeClass

def speak(self):
    return "ook ook eee eee eee!"

SomeClass.speak = speak

Source: MonkeyPatch page on Zope wiki.

Paolo
  • 20,112
  • 21
  • 72
  • 113
168

What is a monkey patch?

Simply put, monkey patching is making changes to a module or class while the program is running.

Example in usage

There's an example of monkey-patching in the Pandas documentation:

import pandas as pd
def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

To break this down, first we import our module:

import pandas as pd

Next we create a method definition, which exists unbound and free outside the scope of any class definitions (since the distinction is fairly meaningless between a function and an unbound method, Python 3 does away with the unbound method):

def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

Next we simply attach that method to the class we want to use it on:

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class

And then we can use the method on an instance of the class, and delete the method when we're done:

df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

Caveat for name-mangling

If you're using name-mangling (prefixing attributes with a double-underscore, which alters the name, and which I don't recommend) you'll have to name-mangle manually if you do this. Since I don't recommend name-mangling, I will not demonstrate it here.

Testing Example

How can we use this knowledge, for example, in testing?

Say we need to simulate a data retrieval call to an outside data source that results in an error, because we want to ensure correct behavior in such a case. We can monkey patch the data structure to ensure this behavior. (So using a similar method name as suggested by Daniel Roseman:)

import datasource

def get_data(self):
    '''monkey patch datasource.Structure with this to simulate error'''
    raise datasource.DataRetrievalError

datasource.Structure.get_data = get_data

And when we test it for behavior that relies on this method raising an error, if correctly implemented, we'll get that behavior in the test results.

Just doing the above will alter the Structure object for the life of the process, so you'll want to use setups and teardowns in your unittests to avoid doing that, e.g.:

def setUp(self):
    # retain a pointer to the actual real method:
    self.real_get_data = datasource.Structure.get_data
    # monkey patch it:
    datasource.Structure.get_data = get_data

def tearDown(self):
    # give the real method back to the Structure object:
    datasource.Structure.get_data = self.real_get_data

(While the above is fine, it would probably be a better idea to use the mock library to patch the code. mock's patch decorator would be less error prone than doing the above, which would require more lines of code and thus more opportunities to introduce errors. I have yet to review the code in mock but I imagine it uses monkey-patching in a similar way.)

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
  • so is the burden on the monkeypatcher to store a reference to the real method? e.g., what happens if one forgets the "retain a pointer" step, it is lost? – Tommy Jan 24 '17 at 16:33
  • 3
    @Tommy If refcounts to an "overwritten" method go to zero - it is garbage collected, and thus "lost" for the life of the process (or unless the module it originated in is reloaded, but that is usually discouraged). – Russia Must Remove Putin Jan 24 '17 at 16:36
41

According to Wikipedia:

In Python, the term monkey patch only refers to dynamic modifications of a class or module at runtime, motivated by the intent to patch existing third-party code as a workaround to a bug or feature which does not act as you desire.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
21

First: monkey patching is an evil hack (in my opinion).

It is often used to replace a method on the module or class level with a custom implementation.

The most common usecase is adding a workaround for a bug in a module or class when you can't replace the original code. In this case you replace the "wrong" code through monkey patching with an implementation inside your own module/package.

  • 9
    In case some modules monkey-patching the same thing: you are doomed. –  Apr 11 '11 at 19:17
  • 61
    While its power could indeed be dangerous in general, it is great for testing – dkrikun Oct 25 '13 at 16:42
  • 3
    The most common usecase is actually for testing, especially unit tests. You want to test only your code, so you patch any external call to return an expected result. – brocoli Sep 26 '17 at 18:12
  • 7
    it isn't evil, I use it to patch bugs in other peoples' software until a new release comes out instead of forking and creating a new dependency. – nurettin Apr 30 '19 at 09:18
  • 2
    Monkey patching can be done in a "pure functional way" not the mutable, "context-sensitive", goto-like way by only doing patching inside decorators that return a new patched version of your class / method (rather than modifying it). A lot of C# / Java programmers don't know about REPL driven development, so they code in their IDEs that requires that everything be statically defined. Since C#/Java didn't have monkey-patching, they assume its evil when they see it in JavaScript, Smalltalk, Lisp, Python, etc... as it goes against their static IDE driven development practice. – aoeu256 Sep 09 '19 at 16:45
  • 1
    If you try to compose decorators that patch in things of the same name you are screwed, I guess its like inheritance or mutability in general. In that case it would be better to just compose your objects and manually delegate things out. I wish Python could tell the difference between defining things (a: 4) and updating them (a := 4), as this could be a big source of bugs. However, in languages that could tell the difference, when you try to compose decorators that both patch-in the same members you could get an error forcing you to rename your things. – aoeu256 Sep 09 '19 at 17:27
  • @aoeu256 at that point I think it's no longer called "monkey-patching"; it's just called "a sub-class" – JamesTheAwesomeDude May 08 '21 at 22:47
  • A class decorator (related to a class factory) can say add logging/database access/asynchronous access/memoization/cache to every method at once, and it can delete methods not just override and extend like subclassing. Think about "cross-cutting concerns" in between methods of all of your classes. Lastly, decorators are run before all of your other code so they can add some sort of "static analysis" like assert that two methods in a class are related by some behavior. – aoeu256 May 10 '21 at 13:39
15

Monkey patching can only be done in dynamic languages, of which python is a good example. Changing a method at runtime instead of updating the object definition is one example;similarly, adding attributes (whether methods or variables) at runtime is considered monkey patching. These are often done when working with modules you don't have the source for, such that the object definitions can't be easily changed.

This is considered bad because it means that an object's definition does not completely or accurately describe how it actually behaves.

Aaron Dufour
  • 17,288
  • 1
  • 47
  • 69
  • 1
    However, monkey patching can be useful as long as instead of modifying an existing object or class, you create a new version of an object with patched in members inside a decorator which screams "hey im going to patch you". – aoeu256 Sep 09 '19 at 16:38
  • You can use annotations on patched members to store in the patched member which decorator was used to patch in the patches. Lets say you have a undoable decorator that creates a new undoable version of a function object with an undo method. You can put in the decorator a patcher field pointing to your undoable decorator. – aoeu256 Sep 09 '19 at 17:09
6

Monkey patching is reopening the existing classes or methods in class at runtime and changing the behavior, which should be used cautiously, or you should use it only when you really need to.

As Python is a dynamic programming language, Classes are mutable so you can reopen them and modify or even replace them.

kamal
  • 996
  • 15
  • 25
6

What is monkey patching? Monkey patching is a technique used to dynamically update the behavior of a piece of code at run-time.

Why use monkey patching? It allows us to modify or extend the behavior of libraries, modules, classes or methods at runtime without actually modifying the source code

Conclusion Monkey patching is a cool technique and now we have learned how to do that in Python. However, as we discussed, it has its own drawbacks and should be used carefully.

akash kumar
  • 121
  • 1
  • 6