Сегодня я увидел одно выражение, которое не выдавало исключение. Может ли кто-нибудь объяснить теорию за этим?
>>> x, y = {'a': 2, 'b': 5}
>>> x
'a'
>>> y
'b'
Сегодня я увидел одно выражение, которое не выдавало исключение. Может ли кто-нибудь объяснить теорию за этим?
>>> x, y = {'a': 2, 'b': 5}
>>> x
'a'
>>> y
'b'
В Python каждый iterable может быть распакован 1:
>>> 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)
>>>
Кроме того, поскольку итерация по словарю возвращает только его ключи:
>>> for i in {1:'a', 2:'b', 3:'c'}:
... print i
...
1
2
3
>>>
распаковка словаря (который итерации по нему) также распаковывает только его ключи.
1 Собственно, я должен сказать, что каждый итеративный может быть распакован, если имена для распаковки равны длине итерации:
>>> 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
>>>
Но это касается только Python 2.x. В Python 3.x у вас есть расширенная итеративная распаковка, которая позволяет распаковать итерируемый любой (конечный) размер только на нужные вам имена:
>>> # 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)
>>>
Итерация a dict
повторяется по клавишам. Так как ваш dict literal имеет ровно два ключа, вы можете распаковать его в 2-х кортежей.
Это, вероятно, не очень хорошая практика в целом, так как dicts неупорядочены, а x == 'b'
и y == 'a'
будут префектно законным результатом этого кода.
когда вы перебираете словарь, вы получаете его ключи
data = {'a': 2, 'b': 5}
for key in data:
print key
Распаковка - это не что иное, как итерация над объектом и помещение элементов в заданные переменные:
keys = tuple(data) # gives ('a', 'b')
x, y = ('a', 'b')
Никакой ракетной науки не стоит. dict
является итерируемым, который возвращает ключи на каждой итерации. tuple()
может принимать любой итеративный аргумент (если они конечны), поэтому:
>>>tuple({'a': 2, 'b': 5})
('a','b')
Увидев это, легко сделать вывод, что распаковка будет работать, как показано. Более того, любой конечный итерируемый может быть распакован:
>>> i = iter(range(3))
>>> a,b,c = i
>>> a,b,c
(0, 1, 2)
Когда в итерированном контексте, dicts рассматривается как (неупорядоченная) коллекция ключей, это то, что вы получаете, когда выполняете list(some_dict)
, что совпадает с вызовом keys()
на dict:
>>> d = {'a': 3, 'b': 5}
>>> list(d)
['a', 'b']
>>> d.keys()
['a', 'b']
Однако вы также можете сделать больше.
Вы можете распаковать оба dict
оба ключа и значения, если сначала включить его в список пар:
>>> d = {'a': 3, 'b': 5}
>>> d_pairs = d.items()
>>> print d_pairs
[('a', 3), ('b', 5)]
>>> ((k1, v1), (k2, v2)) = d_pairs
>>> print k1, v1, k2, v2
a 3 b 5
или если вам просто нужны пары
>>> p1, p2 = d_pairs
>>> print p1, p2
('a', 3) ('b', 5)
или, скажем, только клавиши:
>>> ((k1, _), (k2, _)) = d_pairs
>>> print k1, k2
a b
и др.
Но, разумеется, поскольку словари - и я имею в виду, в общем, не только в Python - содержат свои элементы в некорректном порядке, items()
(в Python) также возвратит их в кажущемся произвольном порядке и, следовательно, там не знает, какой ключ будет храниться в какой переменной:
>>> ((k1, v1), (k2, v2)) = {'bar': 3, 'foo': 5}.items()
>>> print k1, v1, k2, v2
foo 5 bar 3
Как вы видите, порядок пар, возвращаемых items()
, был отменен по сравнению с их порядком определения.