2

Note: code examples in python3, but the question stands for python2 as well (replacing .keys with .viewkeys, etc)

dict objects provide view methods which (sometimes) support set operations:

>>> {'a': 0, 'b': 1}.keys() & {'a'}
{'a'}
>>> {'a': 0, 'b': 1}.items() & {('a', 0)}
{('a', 0)}

But the values view 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 a dict value can be a non-hashable object, so it is not always possible to make a set of the values, however the same is true for dict.items, and here the set operations only fail at runtime for .items once there is an unhashable type in the dict, whereas the set operation for .values fails immediately.

The docs mention that Values views are not treated as set-like since the entries are generally not unique, but this doesn't seem to be a convincing reason - python doesn't for example prevent you from creating a set literal like {0, 0, 1, 2}.

What is the real reason for this inconsistency in behaviour?

wim
  • 338,267
  • 99
  • 616
  • 750
  • The set literal will ignore the duplicates however. You don't want that to happen in a dict view, generally speaking. – Martijn Pieters Jul 10 '14 at 13:39
  • @MartijnPieters I'm not convinced, a set intersection of a dictview and a set returns another set, so what would be wrong with the duplicates being removed at this stage? The dictview can of course still contain dupes. – wim Jul 10 '14 at 13:43
  • 1
    Explicit is better than implicit; convert the values dictionary view to a set then. – Martijn Pieters Jul 10 '14 at 13:50
  • @MartijnPieters do you think that it _could_ have been implemented, theoretically, it simply hasn't been done by design choice? – wim Jul 10 '14 at 13:56
  • 1
    The [original PEP](http://legacy.python.org/dev/peps/pep-3106/) makes no mention of it. But the behaviour would have to be consistent and not suddenly fail for non-hashable types, etc. Requiring an explicit conversion to a set makes that **much** clearer, fitting in the Python design philosophy. – Martijn Pieters Jul 10 '14 at 14:03
  • Fair enough, I guess there are several other implicit conversions possible in python2 which also got banned in python3 – wim Jul 10 '14 at 15:08

4 Answers4

3

If we were to treat the values as a set, you'd make the values dictionary view a very costly object to produce. You have to calculate the hash of all values before you can use it as a set; you really don't want to do this for a large dictionary, especially if you don't know up front if all values are even hashable.

As such, this is far better left as an explicit operation; if you want to treat the values as a set, explicitly make it a set:

values = set(yourdict.values())

The dict.items() behaviour stems from the fact that we know up-front that the keys at least are unique, so each (key, value) pair is unique too; under the covers you can delegate membership testing to the keys dictionary view.

But as soon as you use set operations on that (intersection, union, etc.) you are creating a new set object, not a dictionary view. And for such a set object both elements in the (key, value) pair must be hashable, as the generic set type cannot make the same assumption about the keys, nor could you maintain that constraint (as {'a': 0}.items() & {('a', 1)} is perfectly legal but leads to duplicate keys).

wim
  • 338,267
  • 99
  • 616
  • 750
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0

Because in a dict you can not have repeated keys values, but you can have repeated 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 keys() method return something like cuacks and ducks like a set because you can not have repeated keys on the dict, but you can have repeated values on values(). That's why keys cuacks and ducks like a set but values cuacks and ducks like a list.

vz0
  • 32,345
  • 7
  • 44
  • 77
  • And so what? I'm not saying dupes should be removed from the values view. I'm saying that they should support set operations if there is no unhashable type preventing that. – wim Jul 10 '14 at 13:44
  • @wim It has nothing to do with values being hashable, that is only relevant to the elements as keys to the dict. The keys() method return something like cuacks like a `set` because you can not have repeated keys on the dict. That's why keys ducks like a set but values ducks like a list. – vz0 Jul 10 '14 at 13:48
0

The reason is that it's not implemented in the dict_values type or because the dict_values class specifically disallows it.

Since your values are generally a non-unique list of items it's not a great idea to convert it to a set. If you do want that, just manually convert it. My assumption is that it's disallowed since it's generally a bad idea as it can cause data loss.

Wolph
  • 78,177
  • 11
  • 137
  • 148
-2

If you are coding in leetcode, then you can make it by changing the result from

return res_dic.values()

to

return list(res_dic.values())
Xincan Lv
  • 5
  • 1