2014-04-24 9 views
61

Dzisiaj zobaczyłem jedno stwierdzenie, które nie rzuciło wyjątku. Czy ktoś może wyjaśnić tę teorię?Dlaczego można rozpakować słownik jako krotkę?

>>> x, y = {'a': 2, 'b': 5} 
>>> x 
'a' 
>>> y 
'b' 
+1

Ponieważ nie jest to wspomniane poniżej, powiem, że na decyzję o projekcie prawdopodobnie wpłynęła użyteczność. Kiedy dyktuje ci klucze, domyślnie daje ci dostęp do jego wartości. Jeśli zamiast tego zwróci wartości, trudniej będzie uzyskać dostęp do kluczy. –

Odpowiedz

63

W Pythonie co iterable mogą być rozpakowane :

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

Ponadto, ponieważ kolejno po słowniku powróci tylko jego klawiszy:

>>> for i in {1:'a', 2:'b', 3:'c'}: 
...  print i 
... 
1 
2 
3 
>>> 

rozpakowanie słowniku (który iteruje nad nim) podobnie rozpakowuje tylko jego klucze.


Właściwie powinienem powiedzieć, że każdy może iterable być rozpakowane Dopóki nazwiska rozpakować do równa długości 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 
>>> 

Ale to dopiero case dla Pythona 2.x. W Pythonie 3.x, masz extended iterable unpacking, który pozwala rozpakować iterowalny dowolnej wielkości (skończonych) w ciągu zaledwie nazwami potrzebujesz:

>>> # 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) 
>>> 
+0

Myślę, że to oznacza, że ​​każda iteracja może zostać rozpakowana? – aIKid

+1

Tak, ale zwykle nie ma sensu dla iterables, które są zmienne (zarówno pod względem długości i zawartości), a jeszcze mniej dla iterables nieuporządkowanych. Nie miałbyś możliwości odebrania tego, który klucz został zawarty w miejscu, a żaden sposób dostarczania ci nie dostarczył wystarczającej ilości zmiennych do rozpakowania. – aruisdante

+2

@aikid, nie te nieskończone –

20

iteracji a dict iteracje nad klawiszami. Ponieważ twój literał dosłowny ma dokładnie dwa klucze, możesz rozpakować go do 2-krotnej.

Prawdopodobnie nie jest to dobra praktyka, ponieważ dyktanda są nieuporządkowane, a x == 'b' i y == 'a' byłyby idealnym wynikiem prawnym tego kodu.

+0

Dzięki za wzmiankę o tym, że są nieuporządkowane. – Tarik

+0

Od Pythona 3.6, dyktury są uporządkowane. – gerrit

+0

@gerrit: tak, w cpython, jako szczegół implementacji. – geoffspear

7

Brak nauki o rakietach. dict jest iteracją, która zwraca klucze w każdej iteracji. tuple() może otrzymać każdy iterable jako argument (o ile są skończone), więc:

>>>tuple({'a': 2, 'b': 5}) 
('a','b') 

Widząc to jest łatwo wywnioskować, że rozpakowanie zadziała jak pokazano. Ponadto każda skończony iterable mogą być rozpakowane:

>>> i = iter(range(3)) 
>>> a,b,c = i 
>>> a,b,c 
(0, 1, 2) 
+0

podobnie możemy użyć '>>> listy ({'a': 2, 'b': 5})' :) –

+0

Brak nauki o rakietach: D! +1 –

8

gdy iteracyjne nad słownikiem, masz jej klucze

data = {'a': 2, 'b': 5} 
for key in data: 
    print key 

Rozpakowanie to nic innego niż iteracji nad obiektem i umieścić elementy w podane zmienne:

keys = tuple(data) # gives ('a', 'b') 
x, y = ('a', 'b') 
5

W kontekście iterowalnym dykta jest traktowana jako (nieuporządkowana) kolekcja kluczy, co stanowi w kura zrobić list(some_dict), która jest taka sama jak wywołanie keys() na dict:

>>> d = {'a': 3, 'b': 5} 
>>> list(d) 
['a', 'b'] 
>>> d.keys() 
['a', 'b'] 

Jednak można również zrobić więcej.

można rozpakować zarówno dict „s oba klawisze i wartości jeśli przekształcić go w liście parach pierwszy:

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

lub jeśli po prostu chcesz pary

>>> p1, p2 = d_pairs 
>>> print p1, p2 
('a', 3) ('b', 5) 

lub, powiedzmy, po prostu klucze:

>>> ((k1, _), (k2, _)) = d_pairs 
>>> print k1, k2 
a b 

itd.

Ale oczywiście, ponieważ słowniki - i ogólnie rozumiem, nie tylko w Pythonie - zawierają swoje pozycje w nie uporządkowany sposób, items() (w języku Python) również zwrócą je w pozornie arbitralnej kolejności, a zatem istnieje ma sposobu, aby wiedzieć, który klucz będzie przechowywany w tym o zmiennej:

>>> ((k1, v1), (k2, v2)) = {'bar': 3, 'foo': 5}.items() 
>>> print k1, v1, k2, v2 
foo 5 bar 3 

Jak widać, kolejność par zwróconych przez items() został odwrócony w stosunku do kolejności ich definicji.

+1

+1 za wzmiankę o zamawianiu niekoniecznie jest zachowany w stanie nienaruszonym, gdy rozpakowywanie. –

Powiązane problemy