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 however, d.keys()
and d.values()
both return a list
per the documentation therefore this restriction does not apply. Since they are both the same type of object, it makes sense the same operation will work on both. If you used viewkeys
and viewvalues
as mentioned in the documentation of dict-view objects in Python2.7, then you can expect similar behaviour:
# 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