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?

+2


source to share


4 answers


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).

+3


source


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

.

0


source


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.

0


source


If you are coding in Leetcode, then you can do it by changing the result from

return res_dic.values()

      

in

return list(res_dic.values())

      

0


source







All Articles