当前位置:  开发笔记 > 编程语言 > 正文

为什么OrderedDict的值不相等?

如何解决《为什么OrderedDict的值不相等?》经验,为你挑选了3个好方法。

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



1> bruno desthu..:

在Python 3,dict.keys()dict.values()退回特殊迭代类-分别为collections.abc.KeysViewcollections.abc.ValuesView.第一个继承它的__eq__方法set,第二个使用默认object.__eq__测试对象标识.


虽然这可能确实是答案,但这是一个非常不满意的答案......
我想不要覆盖`object .__ eq__`的决定是有道理的,因为它与你所比较的模糊不清.如果两个`ValueView在任何顺序中包含相同的值,它们是否相等?它应该独立于键吗?根据你想要的东西,比较`.items()`或者将值放在列表或集合中并比较它们会更清楚.
对我来说似乎是一个缺陷.你是否碰巧知道是否有意改写`__eq__`是故意还是只是疏忽?
@RobKennedy不是最简单的想法 - 但Python是免费软件,所以没有什么能阻止你提交补丁;)

2> BigOther..:

在python3,d1.values()并且d2.values()collections.abc.ValuesView对象:

>>> d1.values()
ValuesView(OrderedDict([('foo', 'bar')]))

不要将它们作为对象进行比较,将它们转换为列表然后进行比较:

>>> list(d1.values()) == list(d2.values())
True

调查为什么它用于比较_collections_abc.pyCPython中的键,KeysView是继承SetValuesView不是:

class KeysView(MappingView, Set):

class ValuesView(MappingView):

寻找__eq__in ValuesView及其父母:

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

__eq__仅在实现中object而不是被覆盖.

另一方面,直接KeysView继承.__eq__Set


@bgusach它不是迭代器,但它是可迭代的.请参阅[查看对象](https://docs.python.org/3/library/stdtypes.html#dict-views).
`values()`返回python 3上的迭代器,以及python 2.7中的列表
@PeterWood,我认为`值'相当于`itervalues`,但你是对的,它们不是.

3> Jim Fasaraki..:

不幸的是,当前的两个答案都没有解决为什么这样做,而是集中在如何做到这一点上。该邮件列表讨论非常了不起,所以我总结一下:

对于odict.keys/ dict.keysodict.items/ dict.items

odict.keys(的(的子类dict.keys)支持比较),因为它符合collections.abc.Set(是一个类似集合的对象)。这可能是由于以下事实:keys保证字典内部(有序或无序)是唯一且可哈希的。

odict.items(的子类dict.items)也出于相同的原因支持比较.keysitemsview允许这样做,因为如果items中的一个(特别是表示该值的第二个元素)不可哈希,则会引发适当的错误,但可以保证唯一性,但是(由于keys唯一):

>>> od = OrderedDict({'a': []})
>>> set() & od.items()
TypeErrorTraceback (most recent call last)
 in ()
----> 1 set() & od.items()

TypeError: unhashable type: 'list'

对于这两个视图keysitems比较使用一个称为all_contained_in(非常易读)的简单函数,该函数使用objects __contain__方法检查所涉及视图中元素的成员资格。

现在,关于odict.values/ dict.values

如前所述,odict.values([shocker]的子类dict.values)不像集合对象那样进行比较。这是因为valuesa的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毫秒为单位学习。)

推荐阅读
虎仔球妈_459
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有