为什么OrderedDict的值不相等?
用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.5testing过了。
在这个问题之后,我在Python-Ideas邮件列表上发布了更多的细节:
https://mail.python.org/pipermail/python-ideas/2015-December/037472.html
在Python 3中, dict.keys()和dict.values()返回特殊的可迭代类 – 分别是一个collections.abc.KeysView和一个collections.abc.ValuesView 。 第一个从setinheritance它的__eq__方法,第二个使用默认object.__eq__ ,它testing对象标识。
在python3中, d1.values()和d2.values()是collections.abc.ValuesView对象:
>>> d1.values() ValuesView(OrderedDict([('foo', 'bar')]))
不要把它们作为一个对象进行比较,把它们转换成列表,然后比较它们:
>>> list(d1.values()) == list(d2.values()) True
调查CPython的KeysView中_collections_abc.py的比较原因, KeysViewinheritanceSet而ValuesView不inheritance:
class KeysView(MappingView, Set): class ValuesView(MappingView):
-
在
ValuesView及其父项中跟踪__eq__:MappingView ==> Sized ==> ABCMeta ==> type ==> object。__eq__只在object实现,不能被覆盖。 -
另一方面,
KeysView直接从Setinheritance__eq__。
不幸的是,目前的两个答案都没有解决这个问题,而是关注如何做到这一点。 那个邮件列表的讨论太棒了,所以我总结一下:
对于odict.keys / dict.keys和odict.items / dict.items :
-
odict.keys(dict.keys子类 )支持比较,因为它符合collections.abc.Set(它是一个集合对象)。 这是可能的,因为词典中的keys(有或没有)保证是唯一和可sorting的。 -
odict.items(odict.items子类 )也支持与.keys相同的原因进行比较。itemsview被允许做到这一点,因为如果其中一个item(特别是代表值的第二个元素)不可散列,那么它会引发适当的错误,但唯一性是有保证的(尽pipe由于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,items,比较使用一个简单的叫做all_contained_in(很可读)的函数,它使用对象__contain__方法检查相关视图中元素的成员资格。
现在,关于odict.values / odict.values :
-
正如所注意到的,
odict.values(odict.values[shocker]的子类 ) 并不像集合对象那样比较。 这是因为valuesview的values不能表示为一个集合,原因有两方面:- 最重要的是,该视图可能包含无法删除的重复项。
- 该视图可能包含不可散列的对象(它本身不足以将视图视为集合对象)。
正如@ user2357112和@abarnett在邮件列表中的评论中所述, odict.values / odict.values是一个多重集合,是一个集合的泛化,允许多个元素的实例。 试图比较这些并不像比较keys或items由于固有的重复,sorting和事实,你可能需要考虑与这些值相对应的密钥。 应该像这样的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])
即使与键对应的值不相同,实际上也是相等的? 也许? 也许不会? 这不是直截了当,将导致不可避免的混乱。
要做的一点是,将这些与keys和items进行比较并不是微不足道的, 在邮件列表中用@abarnett的另一个评论来总结:
如果你认为我们可以定义多层应该做什么,尽pipe没有一个标准的multisettypes或为他们的ABC,并将其应用于值的意见,下一个问题是如何做到这一点比二次时间不可哈希值。 (而且你也不能假定在这里订购。)将价值观视为30秒,然后用你直觉上想要的答案回来,而不是在20毫秒内给出错误的答案是一个改进? (无论哪种方式,你都要学习同样的教训:不要比较价值观,我宁愿在20毫米的时间里学习)。