扩展requests.Response Class的明智方法?

时间:2017-02-21 10:43:14

标签: python-3.x python-requests

我正在尝试延长requests.Response,但我不确定该怎么做。

我想要的是扩展requests.Response。我看到的问题是我必须创建一个全新的库分支,或者至少创建一个自定义适配器并为此实现自定义代码。

我目前正在将响应存储在我的新类的属性中,但这意味着我的自定义APIResponse实际上并不像扩展的requests.Response对象。

这是我目前的虚拟工作。

class APIResponse:
    def __init__(self, req_response, formatted_json=None):
        self._content = req_response._content
        self._response = req_response

    @property
    def response(self):
        return self._response

如上所述,我希望我的自定义类的行为类似于requests.Response对象,并具有一些额外的功能。由于Response对象是在非常低的级别生成的,即HTTPAdapter库中的requests模块,我也必须编写自定义适配器 - 而且,逻辑上也是自定义requests.Sessions类,调用它。

这一切都让我相信我在这里错过了一些东西。

是否有一种合理的方式来扩展request.Response个对象,而没有大量的代码?

我还尝试围绕一个实例化的Response对象“包装”一个类,但它看起来非常h​​acky:

class APIResponse(Response):
    __attrs__ = ['_content', 'status_code', 'headers', 'url', 'history',
                 'encoding', 'reason', 'cookies', 'elapsed', 'request',
                 '_formatted']

    def __init__(self, req_response):
        self._content = req_response._content
        self._content_consumed = req_response._content_consumed
        self.status_code = req_response.status_code
        self.headers = req_response.headers
        self.url = req_response.url
        self.history = req_response.history
        self.encoding = req_response.encoding
        self.reason = req_response.reason
        self.cookies = req_response.cookies
        self.elapsed = req_response.elapsed
        self.request = req_response.request

3 个答案:

答案 0 :(得分:2)

如果您不介意影响requests的其他代码(在同一解释器中),则可以猴子修补Response类:

def patched_func(self, rvalue):
    return rvalue

requests.Response.patched_func = patched_func

resp = requests.get("https://httpbin.org/get")

resp.patched_func("Another value")
# => "Another value"

答案 1 :(得分:1)

在看到“hacky”时首先想到的是它具有工作的优势。

但是,您可能会忘记要使用的方法所需的某些属性:为什么不简单地遍历__dict__属性来创建包装器?

它的外观如下:

class APIResponse(Response):
    def __init__(self, req_response):
        for k, v in req_response.__dict__.items():
            self.__dict__[k] = v

它使代码更紧凑,但我必须承认它仍然非常hacky。

答案 2 :(得分:0)

我知道我参加聚会迟到了,但我自己也在考虑同样的事情,并认为我会分享我的解决方案。

requests.Response 类没有以通常的方式实例化,创建一个空实例,然后使用 setter 方法应用状态。

import requests


class MyResponseSubClass(requests.Response):

    def __init__(self, response: requests.Response):
        self.__setstate__(response.__getstate__())
        pass


r = requests.post('https://httpbin.org/post', data={'key': 'value'})

my_response = MyResponseSubClass(r)

print(my_response.url, my_response.status_code, my_response.reason)

我创建了一个扩展请求子类的子类,然后我可以将响应对象传递给该类。它获取该响应对象的状态,然后将该状态应用于响应子类的新实例化子类。