为什么OrderedDict的值不相等?

时间:2015-12-16 12:55:33

标签: python python-3.x dictionary ordereddictionary

使用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

3 个答案:

答案 0 :(得分:41)

在Python 3中,dict.keys()dict.values()会返回特殊的可迭代类 - 分别为collections.abc.KeysViewcollections.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继承自SetValuesView不会:

class KeysView(MappingView, Set):

class ValuesView(MappingView):
  • 跟踪__eq__及其父母中的ValuesView

    MappingView ==> Sized ==> ABCMeta ==> type ==> object

    __eq__仅在object中实施,不会被覆盖。

  • 另一方面,KeysView直接从__eq__继承Set

答案 2 :(得分:5)

不幸的是,目前的答案都没有解决为什么会这样做,而是关注如何做到这一点。那个邮件列表讨论很棒,所以我总结一下:

odict.keys / dict.keysodict.items / dict.items

  • odict.keyssubclass of dict.keys)支持比较,因为它符合collections.abc.Set(它是一个类似集合的对象)。这是可能的,因为字典中的keys(已订购或未订购)保证是唯一且可清除的。
  • odict.itemssubclass 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.valuessubclass of dict.values [shocker])不会像集合式对象一样进行比较。这是因为odict.values的{​​{1}}无法表示为一组,原因有两方面:

    1. 最重要的是,视图可能包含无法删除的重复项。
    2. 视图可能包含不可清除的对象(它本身不足以不将视图视为像集一样)。

正如@user2357112@abarnett在邮件列表中的评论中所述,values / valuesview是一个多集,即允许多个实例的集合的概括它的元素。 尝试比较这些并不像比较odict.valuesdict.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毫秒内学到这一点。)