在 Python 中,该术语monkey patch
仅指在运行时对类或模块的动态修改,作为初学者,我很难在 python 的上下文中理解该术语。谁能用一个真实的例子向我解释我们到底是怎么做的?
- 类的动态修改
- 在运行时动态修改模块
我坚持一个真实世界的例子(尽可能简单)来了解我们必须在哪些场景中执行此类任务?
在 Python 中,该术语monkey patch
仅指在运行时对类或模块的动态修改,作为初学者,我很难在 python 的上下文中理解该术语。谁能用一个真实的例子向我解释我们到底是怎么做的?
我坚持一个真实世界的例子(尽可能简单)来了解我们必须在哪些场景中执行此类任务?
Monkey-patching 是一种以现有代码将继续运行但行为已修改的方式进行一些全局底层更改的方法。
str
一个改变内置命令行为的非常简单的例子:b.py
def foo(msg):
s = str(msg)
print s, type(s)
一个.py
import b
b.foo('foo')
# monkey-patch
import __builtin__
__builtin__.str = unicode
b.foo('foo')
# Results:
#foo <type 'str'>
#foo <type 'unicode'>
该a
模块使用该str
命令修改了其他代码的行为,通过修补它来unicode
代替使用。这是必要的,因为我们假装我们无法访问b.py
的代码。它可能是一个巨大的包,我们只是使用而无法更改。但是我们可以插入新的代码来改变行为。
>>> 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']
上面的示例使用 gevent.socket 进行套接字操作。如果使用标准套接字模块,则需要 3 倍的时间才能完成,因为 DNS 请求是连续的。在 greenlets 中使用标准的 socket 模块会使 gevent 变得毫无意义,那么构建在 socket 之上的模块和包呢?
这就是猴子修补的目的。gevent.monkey 中的函数小心地将标准套接字模块中的函数和类替换为它们的对应物。这样,即使是不知道 gevent 的模块也可以从在 multi-greenlet 环境中运行中受益。
>>> from gevent import monkey; monkey.patch_socket() >>> import urllib2 # it's usable from multiple greenlets now
使用猴子补丁时有一些现实生活中的例子:
Object.method1()
行为。方法可以返回一个字符串或无。所以这里的猴子补丁来了。您替换method1
为只包含一行代码的存根方法return None
。setattr
函数轻松完成。好吧,这通常意味着您的应用程序架构不好,并且不是一个好的设计决策。