Monkey Patching in python: When we need it?

感情迁移 提交于 2019-11-30 10:21:50

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

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.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!