【问题标题】:Sensible way to extend requests.Response Class?扩展 requests.Response 类的明智方法?
【发布时间】:2017-02-21 10:43:13
【问题描述】:

我正在尝试扩展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 对象是在非常低的级别生成的,即requests 库中的HTTPAdapter 模块,我还必须编写一个自定义适配器——并且从逻辑上讲,还要自定义requests.Sessions 类,它被称为。

这一切都让我相信我在这里遗漏了一些东西。

有没有一种明智的方法来扩展request.Response 对象,而无需大量代码?

我还尝试在实例化的Response 对象周围“包装”一个类,但它看起来很hacky:

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

【问题讨论】:

    标签: python-3.x python-requests


    【解决方案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】:

    如果您不介意根据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"
    

    【讨论】:

      【解决方案3】:

      我知道我在这里聚会迟到了,但我自己也在研究同样的事情,并认为我会分享我的解决方案。

      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)
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多