Monkey Patching in python: When we need it?

前端 未结 2 2091
暗喜
暗喜 2021-01-01 06:57

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

相关标签:
2条回答
  • 2021-01-01 07:15

    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
    
    0 讨论(0)
  • 2021-01-01 07:36

    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.
    0 讨论(0)
提交回复
热议问题