简体   繁体   English

为什么** kwargs映射与不同排序的OrderedDict相等?

[英]Why does the **kwargs mapping compare equal with a differently ordered OrderedDict?

According to PEP 468 : 根据PEP 468

Starting in version 3.6 Python will preserve the order of keyword arguments as passed to a function. 从版本3.6开始,Python将保留传递给函数的关键字参数的顺序。 To accomplish this the collected kwargs will now be an ordered mapping . 为了实现这一点,收集的kwargs现在将是有序映射 Note that this does not necessarily mean OrderedDict . 请注意,这并不一定意味着OrderedDict

In that case, why does this ordered mapping fail to respect equality comparison with Python's canonical ordered mapping type, the collections.OrderedDict : 在这种情况下,为什么这个有序映射无法尊重与Python的规范有序映射类型( collections.OrderedDict相等性比较:

>>> from collections import OrderedDict
>>> data = OrderedDict(zip('xy', 'xy'))
>>> def foo(**kwargs):
...     return kwargs == data
... 
>>> foo(x='x', y='y')  # expected result: True
True
>>> foo(y='y', x='x')  # expected result: False
True

Although iteration order is now preserved, kwargs seems to be behaving just like a normal dict for the comparisons. 虽然现在保留了迭代顺序,但kwargs似乎表现得像比较的普通字典。 Python has a C implemented ordered dict since 3.5 , so it could conceivably have been used directly (or, if performance was still a concern, a faster implementation using a thin subclass of the 3.6 compact dict). 从3.5开始 ,Python有一个C实现的有序字典,因此它可以直接使用(或者,如果性能仍然是一个问题,使用3.6紧凑字典的瘦子类更快的实现)。

Why doesn't the ordered mapping received by a function respect ordering in equality comparisons? 为什么函数接收的有序映射不会在相等比较中遵循排序?

Regardless of what an “ordered mapping” means, as long as it's not necessarily OrderedDict , OrderedDict 's == won't take into account its order. 无论“有序映射”是什么意思,只要它不一定是OrderedDictOrderedDict==就不会考虑它的顺序。 Docs: 文档:

Equality tests between OrderedDict objects are order-sensitive and are implemented as list(od1.items())==list(od2.items()) . OrderedDict对象之间的等式测试是顺序敏感的,并实现为list(od1.items())==list(od2.items()) Equality tests between OrderedDict objects and other Mapping objects are order-insensitive like regular dictionaries. OrderedDict对象和其他Mapping对象之间的等式测试对常规字典顺序不敏感。 This allows OrderedDict objects to be substituted anywhere a regular dictionary is used. 这允许在使用常规字典的任何地方替换OrderedDict对象。

"Ordered mapping" only means the mapping has to preserve order. “有序映射”仅表示映射必须保留顺序。 It doesn't mean that order has to be part of the mapping's == relation. 这并不意味着顺序必须是映射的==关系的一部分。

The purpose of PEP 468 is just to preserve the ordering information. PEP 468的目的只是为了保存订购信息。 Having order be part of == would produce backward incompatibility without any real benefit to any of the use cases that motivated PEP 468. Using OrderedDict would also be more expensive (since OrderedDict still maintains its own separate linked list to track order, and it can't abandon that linked list without sacrificing big-O efficiency in popitem and move_to_end ). 订单成为==一部分会产生向后不兼容性,而不会对任何促使PEP 468的用例产生任何实际好处。使用OrderedDict也会更昂贵(因为OrderedDict仍然维护自己独立的链接列表来跟踪订单,它可以在不牺牲popitemmove_to_end大O效率的情况下放弃该链表。

The answer to your first 'why' is because this feature is implemented by using a plain dict in CPython. 第一个'为什么'的答案是因为这个功能是通过在CPython中使用普通dict来实现的。 As @Ryan's answer points out, this means that comparisons won't be order-sensitive. 正如@ Ryan的答案指出的那样,这意味着比较不会对订单敏感。

The second 'why' here is why this doesn't use an OrderedDict . 第二个“为什么”这就是为什么它不使用OrderedDict

Using an OrderedDict was the initial plan as stated in the first draft of PEP 486. The idea, as stated in this reply , was to collect some perf data to show the effect of plugging in the OrderedDict since this was a point of contention when the idea was floated around before. 使用OrderedDict是PEP 486 初稿中所述的初始计划。如本回复中所述该想法是收集一些性能数据以显示插入OrderedDict的影响,因为这是一个争论的焦点。想法在之前浮现。 The author of the PEP even alluded to the order preserving dict being another option in the final reply on that thread. PEP的作者甚至暗示保留dict的顺序是该主题的最终答复中的另一种选择。

After that, the conversation on the topic seems to have died down until Python 3.6 came along. 在那之后,关于该主题的对话似乎已经消失,直到Python 3.6出现。 When the new dict came, it had the nice side-effect of just implementing PEP 486 out of the box (as this Python-dev thread states ). 当新的dict出现时,它具有开箱即用的PEP 486的良好副作用(正如这个Python-dev线程所述 )。 The specific message in that thread also states how the author wanted the term OrderedDict to be changed to Ordered Mapping. 该线程中的特定消息还说明了作者如何将术语OrderedDict更改为Ordered Mapping。 (This is also when a new commit on PEP 468 , after the initial one, was made) (这也是在最初的PEP 468之后的PEP 468新提交时)

As far as I can tell, this rewording was done in order to allow other implementations to provide this feature as they see fit. 据我所知,这个重写是为了允许其他实现提供他们认为合适的功能。 CPython and PyPy already had a dict that easily implemented PEP 468, other implementations might opt for an OrderedDict , others could go for another form of an ordered mapping. CPython和PyPy已经有了一个可以轻松实现PEP 468的字典,其他实现可能会选择OrderedDict ,其他实现可能会采用另一种形式的有序映射。

That does open the door for a problem, though. 但这确实为问题打开了大门。 It does mean that, theoretically, in an implementation of Python 3.6 with an OrderedDict as the structure implementing this feature, the comparison would be order-sensitive while in others (CPython) it wouldn't. 它确实意味着,理论上,在使用OrderedDict作为实现此功能的结构的Python 3.6的实现中,比较将是对顺序敏感的,而在其他(CPython)中它不会。 (In Python 3.7, all dict s are required to be insertion-ordered so this point is probably moot since all implementations would use it for **kwargs ) (在Python 3.7中,所有的dict都需要按顺序插入,所以这一点可能没有实际意义,因为所有实现都会将它用于**kwargs

Though it does seem like an issue, it really isn't. 虽然看起来确实是一个问题,但事实并非如此。 As @user2357112 pointed out, there's no guarantee on == . 正如@ user2357112指出的那样, ==无法保证。 PEP 468 only guarantees order. PEP 468 保证订单。 As far as I can tell, == is basically implementation defined. 据我所知, ==基本上是实现定义的。


In short, it compares equal in CPython because kwargs in CPython is a dict and it's a dict because after 3.6 the whole thing just worked. 简而言之,它在CPython中比较相同因为CPython中的kwargs是一个dict而且它是一个dict因为在3.6之后整个事情才起作用。

Just to add, if you do want to make this check (without relying on an implementation detail (which even then, won't be in python 3.7)), just do 只是要补充一下,如果你确实想要进行这项检查(不依赖于实现细节(即便如此,也不会在python 3.7中)),只需要做

from collections import OrderedDict
>>> data = OrderedDict(zip('xy', 'xy'))
>>> def foo(**kwargs):
...     return OrderedDict(kwargs) == data

since this is guaranteed to be True. 因为这保证是真的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM