【问题标题】:Python monkey patchingPython猴子补丁
【发布时间】:2012-12-18 23:57:18
【问题描述】:

我需要猴子补丁请求的响应类(版本 1.0.4,截至本问题的当前版本),以添加其他方法。

我有这个代码:

import requests

class Response(requests.models.Response):
    def hmm(self):
        return 'ok'

requests.models.Response = Response

r = requests.get('http://bbc.co.uk')

print r

当原始响应调用 super() 时失败 - https://github.com/kennethreitz/requests/blob/master/requests/models.py#L391

我认为这是因为它变得混乱,因为我已经更换了班级,我觉得我在做一些愚蠢的事情,有什么想法吗?提前致谢。

【问题讨论】:

  • In [2]: requests.__version__ Out[2]: '1.0.4' 你也是这样吗?此代码曾经适用于旧版本的请求
  • 文件 "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/models.py",第 391 行,在 init 中 super(Response, self).__init__() TypeError: super(type, obj): obj must be an instance or subtype of type

标签: python monkeypatching


【解决方案1】:

使用setattr 只是一个快速修复,但它有点难看(但在语义上等同于@Martijn answer):

def hmm(self):
    return 'OK - %s' % self.status_code

setattr(requests.models.Response, 'hmm', hmm)

r = requests.get('http://bbc.co.uk')
print r.hmm()
# prints 
# OK - 200

【讨论】:

    【解决方案2】:

    我认为你不能像这样对那种类型进行猴子补丁。导入requests 时,所有these 模块都被初始化。并且由于整个库一遍又一遍地使用from xy import Request,它将对实际类型有一个精确的引用。只有在那之后,您才替换模型模块中的 Response 类型,因此只有后续的导入会受到影响。

    除非您检查所有模块并手动将它们的响应引用替换为您的新类型,否则它们仍将使用原始的,使您的补丁无用。

    相反,您应该保留原始类型,但按照 Martijn 的建议直接扩展它。

    【讨论】:

    • 谢谢。我将使用 inspect.getmembers 从我的类中获取所有方法并将它们分配给原始类。稍微不那么优雅,但会起作用。
    【解决方案3】:

    你最好直接将你的函数添加到类中:

    def hmm(self):
        return 'ok'
    requests.models.Response.hmm = hmm
    

    这很好用:

    >>> import requests
    >>> def hmm(self):
    ...     return 'ok'
    ... 
    >>> requests.models.Response.hmm = hmm
    >>> r = requests.get('http://bbc.co.uk')
    >>> print r
    <Response [200]>
    >>> r.hmm()
    'ok'
    >>> requests.__version__
    '1.0.4'
    

    【讨论】:

    • 我知道我们 Pythonistas 讨厌 OOP,但是子类化怎么样?
    • @tenfishsticks:您仍然必须用该子类替换Response 类,因为requests API 将返回该类的实例。对于添加方法,将方法添加到现有类中会更简单。
    猜你喜欢
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 2017-10-05
    • 2016-09-01
    • 2012-09-16
    • 2020-01-09
    • 1970-01-01
    • 2010-09-29
    相关资源
    最近更新 更多