Why can a dictionary be unpacked as a tuple?
Today, I saw one statement which didn't throw an exception. Can anyone explain the theory behind it?
>>> x, y = {'a': 2, 'b': 5}
>>> x
'a'
>>> y
'b'
In Python, every iterable can be unpacked1:
>>> x,y,z = [1, 2, 3] # A list
>>> x,y,z
(1, 2, 3)
>>> x,y,z = 1, 2, 3 # A tuple
>>> x,y,z
(1, 2, 3)
>>> x,y,z = {1:'a', 2:'b', 3:'c'} # A dictionary
>>> x,y,z
(1, 2, 3)
>>> x,y,z = (a for a in (1, 2, 3)) # A generator
>>> x,y,z
(1, 2, 3)
>>>
Moreover, because iterating over a dictionary returns only its keys:
>>> for i in {1:'a', 2:'b', 3:'c'}:
... print i
...
1
2
3
>>>
unpacking a dictionary (which iterates over it) likewise unpacks only its keys.
1Actually, I should say that every iterable can be unpacked as long as the names to unpack into equals the length of the iterable:
>>> a,b,c = [1, 2, 3] # Number of names == len(iterable)
>>>
>>> a,b = [1, 2, 3] # Too few names
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
>>>
>>> a,b,c,d = [1, 2, 3] # Too many names
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 3 values to unpack
>>>
But this is only the case for Python 2.x. In Python 3.x, you have extended iterable unpacking, which allows you to unpack an iterable of any (finite) size into just the names you need:
>>> # Python 3.x interpreter
...
>>> a, *b, c = [1, 2, 3, 4]
>>> a, b, c
(1, [2, 3], 4)
>>>
>>> a, *b = [1, 2, 3, 4]
>>> a, b
(1, [2, 3, 4])
>>>
>>> *a, b, c = [1, 2, 3, 4]
>>> a, b, c
([1, 2], 3, 4)
>>>
Iterating a dict
iterates over the keys. Since your dict literal has exactly two keys, you can unpack it into a 2-tuple.
This is probably not a good practice in general, since (before python 3.7, or possibly earlier in some other implementations) dicts are unordered and x == 'b'
and y == 'a'
would be a perfectly legal outcome of that code.
when you iterate over a dictionary, you get its keys
data = {'a': 2, 'b': 5}
for key in data:
print key
Unpacking is nothing else than iterating over the object and put the elements in the given variables:
keys = tuple(data) # gives ('a', 'b')
x, y = ('a', 'b')