I have found that comparing the results of the keys()
and values()
methods of the dict
built-in to themselves results in inconsistent results:
instance = {'one': 1}
instance.values() == instance.values() # Returns False
instance.keys() == instance.keys() # Returns True
Running the above code in Python 2.7 will return True for both calls, leading me to believe that there is some implementation detail in Python 3's dict_values
that causes this strange behaviour.
Is there a reason for this behaviour or have i stumbled upon some obscure bug?
The short answer: class dict_values
doesn't have a __eq__
method implemented, but class dict_keys
does:
>>> d.values().__eq__(d.values())
NotImplemented
>>> d.keys().__eq__(d.keys())
True
Therefore, the d.values()
's ==
comparison evaluates to False
.
The longer answer of why it wasn't implemented is a different one and can be seen with a little more digging on the documentation of dict-view objects. This part seems especially relevant (emphasis mine):
Keys views are set-like since their entries are unique and hashable. If all values are hashable, so that (key, value) pairs are unique and hashable, then the items view is also set-like. (Values views are not treated as set-like since the entries are generally not unique.) For set-like views, all of the operations defined for the abstract base class
collections.abc.Set
are available (for example,==
,<
, or^
).
Since keys must be unique, it makes sense that they are set-like and are supported with the class operations of collections.Set
. Values are not set-like due to non-uniqueness.
In Python 2.7, d.keys()
and d.values()
both return a list
per the documentation, so you'll get ordinary list comparison if you try ==
. Of course, since the lists aren't guaranteed to be in any particular order, the comparison doesn't actually do what you want, but you can perform the comparison if you really want to:
x = {0: 'x', 16: 'x'}
y = {16: 'x', 0: 'x'}
# prints False twice - you'd get True on Python 3.
print x.keys() == y.keys()
print x.items() == y.items()
If you used viewkeys
and viewvalues
as mentioned in the documentation of dict-view objects in Python2.7, then you can expect similar behaviour to Python 3:
# Python 2.7
from collections import Set
# in Python 3.x this would be from collections.abc import Set
d = {"one": 1}
print isinstance(d.viewkeys(), Set)
# True
print isinstance(d.viewvalues(), Set)
# False
print d.viewkeys() == d.viewkeys()
# True
print d.viewvalues() == d.viewvalues()
# False
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With