如何不创建新对象转换Python对象属性类型适配Requests请求头校验?
问题背景
Python的requests库从2.28.0版本开始引入了HTTP请求头的严格类型检查,若使用Enum实例作为请求头字典的键,会抛出InvalidHeader异常:
requests.exceptions.InvalidHeader: Header part (<HttpHeaders.content_encoding: 'X-Content-Encoding'>) from {<HttpHeaders.content_encoding: 'X-Content-Encoding'>: 'gzip'} must be of type str or bytes, not <enum 'HttpHeaders'>
原有的修复方案是通过字典推导式生成新字典,将Enum键转换为对应的字符串值:
myheaders= {xkey.value: xval for xkey, xval in myheaders.items() }
但该方案会创建新的字典实例,虽在小字典场景下影响极小,但并非理想方案。
推荐修复方案
方案一:从源头避免使用Enum实例作为键
直接在初始化字典时使用Enum的value属性,让字典的键从一开始就是字符串类型,无需后续转换,完全避免额外对象创建:
import enum import requests class HttpHeaders(str, enum.Enum): forwarded_for = 'X-Forwarded-For' content_type = 'Content-Type' myheaders = { HttpHeaders.forwarded_for.value: "192.168.0.1", HttpHeaders.content_type.value: "text/plain", } requests.post('http://127.0.0.1:8000', "zima", headers=myheaders)
方案二:自定义适配Enum键的字典类
如果必须保留Enum实例作为字典键的写法,可以自定义一个字典子类,重写遍历相关方法,动态返回Enum的value而无需创建新字典:
import enum import requests class EnumKeyDict(dict): def items(self): # 遍历键值对时,自动将Enum实例转为对应的字符串 return ((k.value if isinstance(k, enum.Enum) else k, v) for k, v in super().items()) def keys(self): # 返回键时自动转换Enum实例 return (k.value if isinstance(k, enum.Enum) else k for k in super().keys()) def __iter__(self): # 迭代字典时返回转换后的键 return (k.value if isinstance(k, enum.Enum) else k for k in super().__iter__()) class HttpHeaders(str, enum.Enum): forwarded_for = 'X-Forwarded-For' content_type = 'Content-Type' myheaders = EnumKeyDict({ HttpHeaders.forwarded_for: "192.168.0.1", HttpHeaders.content_type: "text/plain", }) requests.post('http://127.0.0.1:8000', "zima", headers=myheaders)
该方案通过动态转换替代预转换,不会创建新的字典实例,仅在requests遍历请求头时进行类型适配。
内容的提问来源于stack exchange,提问作者fakej Gazeta.pl
相关产品推荐
相关产品推荐

