【问题标题】:Monkey Patching in python: When we need it?python 中的猴子补丁:我们什么时候需要它?
【发布时间】:2012-08-12 05:14:45
【问题描述】:

在 Python 中,术语monkey patch 仅指在运行时对类或模块的动态修改,作为初学者,我真的很难在 python 的上下文中理解这个术语。谁能用一个真实的例子向我解释一下我们到底是怎么做的?

  1. 类的动态修改
  2. 在运行时动态修改模块

我坚持一个真实世界的例子(尽可能简单)来了解我们必须在哪些场景中执行此类任务?

【问题讨论】:

    标签: python monkeypatching


    【解决方案1】:

    Monkey-patching 是一种在现有代码将继续运行但行为已修改的情况下进行一些全局底层更改的方法。

    一个改变内置str命令行为的非常简单的例子:

    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'>
    

    a 模块使用str 命令修改了其他代码的行为,将其修补为使用unicode。这是必要的,因为我们假装我们无法访问b.py 的代码。它可能是一个巨大的包,我们只是使用而无法更改。但是我们可以插入新的代码来改变行为。

    一个真实世界的例子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']  
    

    上面的示例使用 gevent.socket 进行套接字操作。如果 使用标准插座模块,需要 3 倍的时间才能完成 完成,因为 DNS 请求将是连续的。使用 greenlets 中的标准套接字模块使 gevent 变得毫无意义, 那么构建在 socket 之上的模块和包呢?

    这就是猴子修补的目的。 gevent.monkey 中的函数 小心替换标准套接字模块中的函数和类 与他们的合作伙伴。这样即使是模块 不知道 gevent 可以从在 multi-greenlet 中运行中受益 环境。

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

    【讨论】:

      【解决方案2】:

      使用猴子补丁时有一些现实生活中的例子:

      1. 单元测试。创建存根/模拟修补真实对象以更改其行为以尊重测试需求通常很方便。例如,您想测试Object.method1() 的行为。方法可以返回一个字符串或无。所以这里的猴子补丁来了。您将method1 替换为仅包含一行代码return None 的存根方法。
      2. 代码在运行时修改/扩展。这种用例的最佳示例可能是相当流行的 python gevent 库。它使用猴子补丁来使标准套接字模块按照 gevent 需要的方式工作。这是code的来源。
      3. 在运行时将补丁应用于对象。对对象进行简单快速的修改会很有用,在此之后,对象必须符合应用程序其他部分使用的某些接口。可以使用setattr 函数在 Python 中轻松完成。嗯,这通常意味着您的应用程序架构不佳,并且不是一个好的设计决策

      【讨论】:

      • 创建一个对象的副本然后将补丁(装饰器)应用于副本(纯粹的功能补丁)怎么样?你不需要使用 setattr 你可以这样做:a.method = lambda self: 5.
      猜你喜欢
      • 2012-12-18
      • 1970-01-01
      • 2019-09-07
      • 1970-01-01
      • 2011-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-05
      相关资源
      最近更新 更多