使用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
在Python 3,dict.keys()
并dict.values()
退回特殊迭代类-分别为collections.abc.KeysView
和collections.abc.ValuesView
.第一个继承它的__eq__
方法set
,第二个使用默认object.__eq__
测试对象标识.
在python3,d1.values()
并且d2.values()
是collections.abc.ValuesView
对象:
>>> d1.values() ValuesView(OrderedDict([('foo', 'bar')]))
不要将它们作为对象进行比较,将它们转换为列表然后进行比较:
>>> list(d1.values()) == list(d2.values()) True
调查为什么它用于比较_collections_abc.py
CPython中的键,KeysView
是继承Set
而ValuesView
不是:
class KeysView(MappingView, Set): class ValuesView(MappingView):
寻找__eq__
in ValuesView
及其父母:
MappingView ==> Sized ==> ABCMeta ==> type ==> object
.
__eq__
仅在实现中object
而不是被覆盖.
另一方面,直接KeysView
继承.__eq__
Set
不幸的是,当前的两个答案都没有解决为什么这样做,而是集中在如何做到这一点上。该邮件列表讨论非常了不起,所以我总结一下:
对于odict.keys
/ dict.keys
和odict.items
/ dict.items
:
odict.keys
(的(的子类dict.keys
)支持比较),因为它符合collections.abc.Set
(是一个类似集合的对象)。这可能是由于以下事实:keys
保证字典内部(有序或无序)是唯一且可哈希的。
odict.items
(的子类dict.items
)也出于相同的原因支持比较.keys
。itemsview
允许这样做,因为如果item
s中的一个(特别是表示该值的第二个元素)不可哈希,则会引发适当的错误,但可以保证唯一性,但是(由于keys
唯一):
>>> od = OrderedDict({'a': []}) >>> set() & od.items() TypeErrorTraceback (most recent call last)in () ----> 1 set() & od.items() TypeError: unhashable type: 'list'
对于这两个视图keys
,items
比较使用一个称为all_contained_in
(非常易读)的简单函数,该函数使用objects __contain__
方法检查所涉及视图中元素的成员资格。
现在,关于odict.values
/ dict.values
:
如前所述,odict.values
([shocker]的子类dict.values
)不像集合对象那样进行比较。这是因为values
a的valuesview
不能表示为集合,原因有两个:
最重要的是,该视图可能包含无法删除的重复项。
该视图可能包含不可散列的对象(仅凭其本身就不足以将其视为类似于集合的视图)。
正如@ user2357112和@abarnett在邮件列表中的注释中所述,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])
即使对应于键的值不一样,实际上是相等的吗?也许?也许不吧?这两种方法都不是直接的,并且会导致不可避免的混乱。
但是要指出的是,将它们与keys
和进行比较并不是很items
容易的,总之,还有@abarnett在邮件列表上的另一条评论:
如果您正在考虑尽管没有标准多集类型或ABC的定义,但我们仍可以定义多集应执行的操作并将其应用于值视图,那么下一个问题是,对于非散列而言,如何比二次时间做得更好价值观。(并且您也不能假设在这里订购。)将值视图挂起30秒钟,然后返回您直观地想要的答案,而不是在20毫秒内给出错误的答案,这会有所改善吗?(无论哪种方式,您都将学习同一课:不要比较值视图。我宁愿以20毫秒为单位学习。)