使用Python 3:
>>> from collections import OrderedDict
>>> d1 = OrderedDict([('foo', 'bar')])
>>> d2 = OrderedDict([('foo', 'bar')])
我想检查是否平等:
>>> d1 == d2
True
>>> d1.keys() == d2.keys()
True
可是:
>>> d1.values() == d2.values()
False
你知道为什么价值观不平等吗?
我用Python 3.4和3.5进行了测试。
在提出这个问题之后,我在Python-Ideas邮件列表上发布了其他详细信息:
https://mail.python.org/pipermail/python-ideas/2015-December/037472.html
答案 0 :(得分:41)
在Python 3中,dict.keys()
和dict.values()
会返回特殊的可迭代类 - 分别为collections.abc.KeysView
和collections.abc.ValuesView
。第一个从__eq__
继承它的set
方法,第二个使用默认的object.__eq__
来测试对象标识。
答案 1 :(得分:19)
在python3中,d1.values()
和d2.values()
是collections.abc.ValuesView
个对象:
>>> d1.values()
ValuesView(OrderedDict([('foo', 'bar')]))
不要将它们作为对象进行比较,c 将它们转换为列表然后进行比较:
>>> list(d1.values()) == list(d2.values())
True
调查CPython的_collections_abc.py
中比较密钥的原因,KeysView
继承自Set
而ValuesView
不会:
class KeysView(MappingView, Set):
class ValuesView(MappingView):
跟踪__eq__
及其父母中的ValuesView
:
MappingView ==> Sized ==> ABCMeta ==> type ==> object
。
__eq__
仅在object
中实施,不会被覆盖。
另一方面,KeysView
直接从__eq__
继承Set
。
答案 2 :(得分:5)
不幸的是,目前的答案都没有解决为什么会这样做,而是关注如何做到这一点。那个邮件列表讨论很棒,所以我总结一下:
odict.keys
/ dict.keys
和odict.items
/ dict.items
:
odict.keys
(subclass of dict.keys
)支持比较,因为它符合collections.abc.Set
(它是一个类似集合的对象)。这是可能的,因为字典中的keys
(已订购或未订购)保证是唯一且可清除的。 odict.items
(subclass of dict.items
)也支持比较,原因与.keys
相同。允许itemsview
执行此操作,因为如果其中一个item
(特别是表示该值的第二个元素)不可哈希,则会引发相应的错误,但保证唯一性(由于{{ 1}}独特):
keys
对于这些视图>>> od = OrderedDict({'a': []})
>>> set() & od.items()
TypeErrorTraceback (most recent call last)
<ipython-input-41-a5ec053d0eda> in <module>()
----> 1 set() & od.items()
TypeError: unhashable type: 'list'
,keys
,比较使用一个名为all_contained_in
(非常易读)的简单函数,该函数使用对象items
方法检查其成员身份所涉及的观点中的要素。
现在,关于__contain__
/ odict.values
:
正如所注意到的,dict.values
(subclass of dict.values
[shocker])不会像集合式对象一样进行比较。这是因为odict.values
的{{1}}无法表示为一组,原因有两方面:
正如@user2357112和@abarnett在邮件列表中的评论中所述,values
/ valuesview
是一个多集,即允许多个实例的集合的概括它的元素。
尝试比较这些并不像比较odict.values
或dict.values
那样简单,因为固有的重复,排序以及您可能需要考虑与这些值对应的键的事实。 keys
应该是这样的:
items
实际上是相等的,即使与键对应的值不相同?也许?也许不吧?这不是直截了当的,会导致不可避免的混乱。
要说明的一点是,将这些与dict_values
和>>> {1:1, 2:1, 3:2}.values()
dict_values([1, 1, 2])
>>> {1:1, 2:1, 10:2}.values()
dict_values([1, 1, 2])
进行比较并不是一件容易的事,总结一下,来自the mailing list的@abarnett的另一条评论:
如果您认为我们可以定义多集合应该做什么,尽管没有标准的多集类型或ABC,并将其应用于值视图,下一个问题是如何在优于二次时间的情况下执行此操作不可拆卸的价值观。 (而且你也不能假设在这里订购。)如果有一个值视图挂起30秒然后回到你想要的答案而不是在20毫米中给出错误的答案是一个改进吗? (无论哪种方式,你都会学到同样的教训:不要比较价值观。我宁愿在20毫秒内学到这一点。)