Why does the OrderedDict
keys view compare order-insensitive?
>>> from collections import OrderedDict
>>> xy = OrderedDict([('x', None), ('y', None)])
>>> yx = OrderedDict([('y', None), ('x', None)])
>>> xy == yx
False
>>> xy.keys() == yx.keys()
True
The OrderedDict keys view should arguably behave like an OrderedSet, but instead it behaves the same as dict.keys
(i.e. like a usual set
).
Same "issue" in python2:
>>> xy.viewkeys() == yx.viewkeys()
True
They are different types, (odict_keys
is a subclass of dict_keys
)
>>> type(xy.keys())
odict_keys
>>> type({}.keys())
dict_keys
And there is already an order-sensitive keys comparison available that they could have trivially used, but it's apparently only used as a post-check for the odict rich comparison.
Is this a design decision, or a bug? If it's a design decision, where could I find a discussion of the justification?
Looks like
OrderedDict
delegates the implementation of the various view objects to the commondict
implementation; this remains the case even in Python 3.5 whereOrderedDict
gained a C accelerated implementation (it delegates object construction to_PyDictView_New
and provides no override for the generic view's rich comparison function.Basically,
OrderedDict
views iterate with the same order their backingOrderedDict
would (because there is no cost to do so), but forset
-like operations, they act likeset
, using content equality, subset/superset checks, etc.This makes the choice to ignore ordering make sense to some extent; for some
set
operations (e.g.&
,|
,^
), the return value is aset
without order (because there is noOrderedSet
, and even if there were, which ordering do you use for something like&
where the ordering may be different in each view?), you'd get inconsistent behaviors if some of theset
-like operations were order sensitive and some weren't. And it would be even weirder when twoOrderedDict
keys views were order sensitive, but comparingOrderedDict
views todict
views wasn't.As I noted in the comments, you can get order sensitive
keys
comparison pretty easily with:I can't find anything published, but I guess this logic could justify the behaviour:
If you have two dictionaries, d1 and d2, you'd expect that comparing the keys checks whether they have the same keys, right?
This function should behave the same way for any types of dictionary (and
OrderedDict
is a type ofdict
). It would seem wrong if such a function started returningFalse
just because d1 and d2 are sorted.In other words, these should all evaluate the same (and they do):
But
OrderedDict
is specal, isn't it?What
OrderedDict
does offer you is the guarantee of order when you iterate through it. The same guarantee exists forOrderedDict.keys()
, but without breaking the compatibility withdict
.