2014-04-24 17 views
61

Oggi ho visto una dichiarazione che non ha fatto eccezione. Qualcuno può spiegare la teoria dietro di esso?Perché un dizionario può essere decompresso come una tupla?

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

Dal momento che non è menzionato di seguito, dirò che questa decisione di progettazione è stata probabilmente influenzata dall'utilità. Quando un dict ti dà le sue chiavi, ti dà implicitamente l'accesso ai suoi valori. Se invece restituisse i suoi valori, sarebbe più difficile accedere alle sue chiavi. –

risposta

63

In Python, ogni iterable possono essere spacchettati :

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

Inoltre, poiché l'iterazione di un dizionario ritorna solo i tasti:

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

disimballaggio un dizionario (che itera su di esso) allo stesso modo decomprime solo le sue chiavi.


In realtà, dovrei dire che ogni iterabile possono essere spacchettati finchè i nomi per decomprimere in uguale alla lunghezza del iterabile:

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

Ma questa è solo la caso per Python 2.x. In Python 3.x, avete extended iterable unpacking, che permette di decomprimere un iterabile di qualsiasi dimensione (finito) in solo i nomi necessari:

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

Immagino, questo significa che ogni iterabile può essere decompresso? – aIKid

+1

Sì, ma di solito non ha senso per iterabili che sono mutabili (sia per lunghezza che per contenuto) e ancor meno per iterabili non ordinati. Non avresti modo di aggirare la chiave su cui finire e, in nessun modo di aggirarlo, hai fornito abbastanza variabili da disfare. – aruisdante

+2

@aikid, non gli infiniti –

20

Iterazione un dict itera consegna le chiavi. Dal momento che il tuo dict letteral ha esattamente due chiavi, puoi scompattarlo in una tupla da 2.

Questa probabilmente non è una buona pratica in generale, dal momento che i dict non sono ordinati e x == 'b' e y == 'a' sarebbe un risultato prefettatamente legale di quel codice.

+0

Grazie per aver detto che non sono ordinati. – Tarik

+0

A partire da Python 3.6, le istruzioni sono ordinate. – gerrit

+0

@gerrit: sì, in cpython, come dettaglio di implementazione. – geoffspear

7

Nessuna scienza missilistica dietro. dict è un iterabile, che restituisce le chiavi in ​​ogni iterazione. tuple() possono ricevere alcuna iterabile come argomento (finché sono finite), quindi:

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

Vedendo questo, è facile dedurre che disimballaggio funzionerà come mostrato. Inoltre, qualsiasi finita iterabile possono essere spacchettati:

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

allo stesso modo possiamo usare '>>> lista ({'a': 2, 'b': 5})' :) –

+0

Nessuna scienza missilistica: D! +1 –

8

quando eseguire iterazioni su un dizionario, si ottiene le sue chiavi

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

Apertura della confezione non è altro che l'iterazione sopra l'oggetto e mettere gli elementi in le variabili date:

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

Quando nel contesto iterabile, dicts sono trattati come (non ordinato) consegna delle chiavi, che è quello che si ottiene w uando si fa list(some_dict), che è lo stesso di chiamare keys() sul dict:

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

Tuttavia, si può anche fare di più.

È possibile decomprimere sia una s dict' entrambi i tasti e valori se trasformarlo in una lista di coppie prima:

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

o se si desidera solo le coppie

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

o, per dire, solo i tasti:

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

ecc.

Ma ovviamente dato che i dizionari - e in generale, non solo in Python - contengono i loro elementi in maniera non ordinata, items() (in Python) li restituiranno anche in un ordine apparentemente arbitrario, e quindi non c'è c'è modo di sapere quale chiave verrà memorizzato nella quale variabile:

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

Come si vede, l'ordine delle coppie restituite da items() è stata invertita in confronto al loro ordine definizione.

+1

+1 per menzionare l'ordinamento non è necessariamente mantenuto intatto quando disimballaggio. –