Inconsistent behavior between dict.items and dict.values
Note: code examples are in python3, but the question also applies to python2 (replacement .keys
with .viewkeys
, etc.)
Objects dict
provide presentation methods that (sometimes) support set operations:
>>> {'a': 0, 'b': 1}.keys() & {'a'}
{'a'}
>>> {'a': 0, 'b': 1}.items() & {('a', 0)}
{('a', 0)}
But value representation does not support set operators:
>>> {'a': 0, 'b': 1}.values() & {0}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'dict_values' and 'set'
I understand that the dict value may be a non-hashable object, so it is not always possible to create a set of values, however the same is true for dict.items
, and here the set operation .items
only fails at runtime for .items
once the dict has a non-mutable type , whereas the set operation for .values
fails immediately.
The docs mention that Values views are not handled as set-like since records are generally not unique , but that doesn't seem like a compelling reason - for example python doesn't prevent the creation of a set literal like {0, 0, 1, 2}
.
What is the real reason for this discrepancy in behavior?
source to share
If we were to treat values as a collection, you would make representing a dictionary of values a very expensive object. You must compute the hash of all values before using it as a set; You really don't want to do this for a large dictionary, especially if you don't know ahead of time if all values can be hashed.
Thus, it is much better to leave it as an explicit operation; if you want to treat values as a set, explicitly make it a set:
values = set(yourdict.values())
dict.items()
stems from the fact that we dict.items()
know that keys are at least unique, so each pair (key, value) is also unique; under the covers, you can delegate membership testing to a key dictionary view.
But as soon as you use set operations (intersection, union, etc.), you create a new object set
, not a dictionary. And for such an object, set
both elements in a pair (key, value) must be hashable, since a generic type set
cannot make the same assumption about keys, and you cannot support this constraint (as {'a': 0}.items() & {('a', 1)}
perfectly legal, but leads to duplicate keys).
source to share
Because in, dict
you cannot repeat values keys
, but you can have duplicate values values
:
>>> d = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0}
>>> d.keys()
[0, 1, 2, 3, 4]
>>> d.values()
[0, 0, 0, 0, 0]
>>> d.items()
[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)]
The method keys()
returns something like cuacks and ducks like set
, because dict
you cannot duplicate keys on , but you can have duplicate values on values()
. This is why keys
cookies and ducks like a set, but values
cookies and ducks like list
.
source to share
The reason is that it is not implemented in the type, dict_values
or because the class dict_values
specifically disallows it.
Since your values are usually a unique list of items, it's not a great idea to convert it to a set. If you want it, just change manually. My guess is that it is prohibited, as it is generally a bad idea as it could lead to data loss.
source to share