Python 为什么OrderedDict keys视图比较不区分顺序?

Python 为什么OrderedDict keys视图比较不区分顺序?,python,python-3.x,python-internals,ordereddictionary,Python,Python 3.x,Python Internals,Ordereddictionary,为什么orderedictkeys视图比较顺序不敏感 >>> from collections import OrderedDict >>> xy = OrderedDict([('x', None), ('y', None)]) >>> yx = OrderedDict([('y', None), ('x', None)]) >>> xy == yx False >>> xy.keys() == yx.k

为什么
orderedict
keys视图比较顺序不敏感

>>> from collections import OrderedDict
>>> xy = OrderedDict([('x', None), ('y', None)])
>>> yx = OrderedDict([('y', None), ('x', None)])
>>> xy == yx
False
>>> xy.keys() == yx.keys()
True
OrderedDict keys视图的行为应该与OrderedSet类似,但其行为与
dict.keys
相同(即,与通常的
集合

python2中的相同“问题”:

>>> xy.viewkeys() == yx.viewkeys()
True
它们是不同的类型,(
odict_-keys
dict_-keys
的子类)

现在已经有了一个他们可以简单使用的,但它显然只是用来进行odict丰富的比较


这是一个设计决策,还是一个bug?如果是设计决策,我在哪里可以找到对理由的讨论?

看起来像
OrderedDict
将各种视图对象的实现委托给公共
dict
实现;即使在Python3.5中,
OrderedDict
获得了C加速实现(以及通用视图的

基本上,
orderedict
视图以其备份
orderedict
的相同顺序进行迭代(因为这样做没有成本),但对于类似
set
的操作,它们的行为类似于
set
,使用内容相等、子集/超集检查等


这使得忽略顺序的选择在某种程度上是有意义的;对于一些
集合
操作(例如
&
|
^
),返回值是一个没有顺序的
集合
(因为没有
OrderedSet
,即使有,在每个视图中排序可能不同的情况下,您对
&
之类的东西使用哪种排序?),如果一些类似于
set
的操作是顺序敏感的,而另一些不是顺序敏感的,则会出现不一致的行为。如果两个
orderedict
键视图是顺序敏感的,而将
orderedict
视图与
dict
视图进行比较则会更加奇怪

正如我在评论中所指出的,您可以很容易地通过以下方式获得订单敏感的
比较:

from operator import eq

# Verify that keys are the same length and same set of values first for speed
# The `all` check then verifies that the known identical keys appear in the
# same order.
xy.keys() == yx.keys() and all(map(eq, xy, yx))

# If you expect equality to occur more often than not, you can save a little
# work in the "are equal" case in exchange for costing a little time in the
# "not even equal ignoring order case" by only checking length, not keys equality:
len(xy) == len(yz) and all(map(eq, xy, yx))

我找不到任何已发表的文章,但我想这种逻辑可以证明这种行为的合理性:

如果你有两个字典,d1和d2,你会期望比较键来检查它们是否有相同的键,对吗

def compare_dict_keys(d1, d2):
    d1.keys() == d2.keys()
对于任何类型的字典,此函数的行为都应该相同(并且
OrderedDict
dict
的一种类型)。如果仅仅因为d1和d2被排序,这样的函数开始返回
False
,那么它似乎是错误的

换句话说,它们的评估结果应该是相同的(它们确实如此):

但是
OrderedDict
是特殊的,不是吗?


OrderedDict
为您提供的是迭代时的订单保证。同样的保证也适用于
OrderedDict.keys()
,但在不破坏与
dict的兼容性的情况下

如果您热衷于解决此问题,因为您也需要比较订单,您可以将键喷射到列表中并进行比较:
list(xy)==list(yx)
@BenjaminHodgson或
all(x==y代表x,y代表zip(xy,yx))
如果您希望python3上的评估稍微慢一点。x@mgilson:您还需要检查
len
,或者使用带有哨兵的
itertools.zip_longest
,或者如果一组键是其他键的截断运行,则返回
True
。您还可以将更多工作推到C层,对除s以外的所有键运行titch更快mallest通过从操作符import eq导入顶部
,然后在测试站点执行
len(xy)==len(yx)和all(map(eq,xy,yx))
来运行,首先验证长度,然后尽可能高效地执行C级键比较。还请注意,其他python实现默认使用有序字典()。使有序dict的
KeysView
行为与常规dict不同可能会使它们的实现更加困难(据我所知,有时在语言决策中会考虑到这一点)。我在Python ideas邮件列表上发布了更多信息:注意,
d1.keys()!=d2.keys()[代码] >不意味着<代码> d1.k2.v2.d2.kEsVIEW()/代码>(Python 2.x)。<
d2={9:9,1:1}
——这里的
.keys()
的结果不相等,但这两个无序的dict有相同的键。实际上,
{1:1,9:9}
{9:9,1:1}
之间没有区别。python 2的问题是
dict.keys()
的比较被破坏了(也就是说,你根本不应该在python 2中执行
d1.keys()==d2.keys()
,因为如果你这样做,你就是在自食其果。@zvone:它没有坏,它只是返回一个复制
dict
键的
列表;没有坏,但对性能有害,也不是你通常需要的。“如果两个OrderedDict键视图都是顺序敏感的,那就更奇怪了,但将OrderedDict视图与dict视图进行比较却不是。“-但是比较有序的dicts和dicts已经有了这种不一致性,导致了可怕的情况,
a==b==c
但是
a!=c
,因为a和c是有序的,而b不是。总之,+1。@user2357112:是的,我并没有说到处都遵循这个原理,只是为了映射视图。:-)
def compare_dict_keys(d1, d2):
    d1.keys() == d2.keys()
>>> {1:2, 3:4}.keys() == {3:4, 1:2}.keys()
True
>>> {1:2, 3:4}.keys() == OrderedDict([(3,4),(1,2)]).keys()
True
>>> OrderedDict([(1,2),(3,4)]).keys() == OrderedDict([(3,4),(1,2)]).keys()
True