Question

In Python, the term monkey patch only refers to dynamic modifications of a class or module at runtime, As a beginner its really difficult to me understand this term in context of python. Can anybody explain to me with a real world example How exactly we do ?

  1. dynamic modifications of a class
  2. dynamic modifications of module at runtime

I am insisting a real world example (as simple as possible) to understand in which scenarios we have to do such task ?

Was it helpful?

Solution

Monkey-patching is a way to make some global under-the-hood change in a way that existing code will continue to run, but with modified behavior.

A really really trivial example of changing the behavior of the builtin str command:

b.py

def foo(msg):
    s = str(msg)
    print s, type(s)

a.py

import b

b.foo('foo')

# monkey-patch 
import __builtin__
__builtin__.str = unicode

b.foo('foo')

# Results:
#foo <type 'str'>
#foo <type 'unicode'>

The a module has modified the behavior of other code using the str command, by patching it to use unicode instead. This would be necessary since we pretend that we have no access to b.py's code. It could have been a huge package that we simply use and can't change. But we can slip in new code to be called that changes the behavior.

A real world example from gevent

>>> import gevent
>>> from gevent import socket
>>> urls = ['www.google.com', 'www.example.com', 'www.python.org']
>>> jobs = [gevent.spawn(socket.gethostbyname, url) for url in urls]
>>> gevent.joinall(jobs, timeout=2)
>>> [job.value for job in jobs]
['74.125.79.106', '208.77.188.166', '82.94.164.162']  

The example above used gevent.socket for socket operations. If the standard socket module was used it would took it 3 times longer to complete because the DNS requests would be sequential. Using the standard socket module inside greenlets makes gevent rather pointless, so what about module and packages that are built on top of socket?

That’s what monkey patching for. The functions in gevent.monkey carefully replace functions and classes in the standard socket module with their cooperative counterparts. That way even the modules that are unaware of gevent can benefit from running in multi-greenlet environment.

>>> from gevent import monkey; monkey.patch_socket()
>>> import urllib2 # it's usable from multiple greenlets now

OTHER TIPS

There are some real life examples when monkey patching is used:

  1. Unit testing. It's often convinient to create stubs/mocks patching real object to change it behaviour to respect testing needs. For example, you want to test Object.method1() behaviour. Method can return a string or None. So here's monkey patching comes. You replace method1 with a stub method containing only one line of code return None.
  2. Code modifying/extening during runtime. Possibly the best example of such use case is rather popular python gevent library. It uses monkey patching to make standard socket module work the way gevent needs it to. Here's a source code.
  3. Apply a patch to an object at runtime. It can be useful to make easy and fast modification to object, which, after that, must conform some interface used by other parts of an application. It can be easilly done in Python using setattr function. Well, this often means bad architecture of your application, and is not a good design decision.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top