Python 如何创建通过items()返回重复值的类似dict的对象 框架
我正在使用该框架生成HTTP/2流量。在生成请求和响应时,我当前使用和分别发送HTTP/2请求和响应 我的要求 我需要能够发送带有重复字段的HTTP/2请求和响应。例如,这里是YAML指定的请求,它包含两个Python 如何创建通过items()返回重复值的类似dict的对象 框架,python,Python,我正在使用该框架生成HTTP/2流量。在生成请求和响应时,我当前使用和分别发送HTTP/2请求和响应 我的要求 我需要能够发送带有重复字段的HTTP/2请求和响应。例如,这里是YAML指定的请求,它包含两个x-test-duplicate字段: headers: fields: - [ :method, GET, equal ] - [ :scheme, https, equal ] - [ :authority, example.data.com, equa
x-test-duplicate
字段:
headers:
fields:
- [ :method, GET, equal ]
- [ :scheme, https, equal ]
- [ :authority, example.data.com, equal ]
- [ :path, '/a/path?q=3', equal ]
- [ Accept, '*/*' ]
- [ Accept-Language, en-us ]
- [ Accept-Encoding, gzip ]
- [ x-test-duplicate, first ]
- [ x-test-duplicate, second ]
- [ Content-Length, "0" ]
注意,根据HTTP/2规范,这是明确允许的。例如,见:
动态表可以包含重复的条目(即带有
相同的名称和值)。因此,不得重复条目
被解码器视为错误
我的问题
问题是,虽然正确处理可能包含重复字段(例如,(“name1”、“value1”)、(“name2”、“value2”)、(“name1”、“另一个值”)
)的元组表,但需要一个字典,当然,它不是为重复键设计的。文档中没有明确说明标题的类型要求,但在源代码中,items()
被取消。如果我传递一个元组的iterable,我会得到AttributeError:“tuple”对象没有属性“items”
。请注意,这是多么可悲:超框架强制用户传入一个不允许重复的字典,然后通过items()
,立即将该字典转换为元组的一个iterable,后者允许重复字段。如果只需要一组元组,比如h2的接口,我就不会有这个问题
我的问题
我在hyper-github项目中提出了关于此限制的问题。同时,我希望我能解决这个问题。我有一个表示HTTP/2头的元组表,其中包含重复的字段。我是否可以将其包装在一个对象中,以便在对其调用items()
时,它只返回元组的iterable?由于Python支持Duck类型,因此具有items
方法的类就足够了:
class Wrapper:
__slots__ = ["pairs"] # Minor optimization
def __init__(self, pairs: Iterable[Tuple[str, str]]):
self.pairs = pairs
def items(self) -> Iterable[Tuple[str, str]]:
return self.pairs
然后:
这方面的主要问题是它完全依赖于请求的实现细节。如果他们将来选择使用标题
用于其他类似dict的目的,这将很容易中断。Python通常使用电子邮件实例来实现这一点()
EmailMessage
类似字典的接口由标题名称索引,标题名称必须是ASCII值。字典的值是带有一些额外方法的字符串。标头以保留大小写的形式存储和返回,但字段名不区分大小写进行匹配。与真正的dict不同,对键有一个顺序,并且可以有重复的键。提供了用于处理具有重复键的标题的其他方法
在基本用法中,您可以使用设置项并使用检索项。您可以将有效负载留空
>>> headers = EmailMessage()
>>> headers.add_header("x-test-duplicate", "first")
>>> headers.add_header("x-test-duplicate", "second")
>>> headers.items()
[('x-test-duplicate', 'first'), ('x-test-duplicate', 'second')]
这是一场经过自身考验的战斗,这是一种挑战
与滚动自己的multidict或使用简单的对列表相比,其优点是可以获得标题的正确行为(RFC 5322和RFC 6532样式字段名和值),例如不区分大小写:
>>> headers.add_header("aBc", "val1")
>>> headers.add_header("AbC", "val2")
>>> headers.get_all("ABC")
['val1', 'val2']
是的,很好。为了明确起见,我已经验证了这确实满足hyper.HTTP20Connection.request(),并导致发送重复的字段。非常感谢。
>>> headers.add_header("aBc", "val1")
>>> headers.add_header("AbC", "val2")
>>> headers.get_all("ABC")
['val1', 'val2']