dict - python{}




Iterare sui dizionari usando i cicli "for" (8)

Iterare sui dizionari usando i cicli "for"

d = {'x': 1, 'y': 2, 'z': 3} 
for key in d:
    ...

In che modo Python riconosce che è sufficiente leggere la chiave dal dizionario? La chiave è una parola speciale in Python? O è semplicemente una variabile?

Non è solo for loop. La parola importante qui è "iterating".

Un dizionario è una mappatura delle chiavi ai valori:

d = {'x': 1, 'y': 2, 'z': 3} 

Ogni volta che iteriamo su di esso, iteriamo sulle chiavi. La key nome della variabile è intesa solo per essere descrittiva - ed è abbastanza adatta allo scopo.

Questo succede in una lista di comprensione:

>>> [k for k in d]
['x', 'y', 'z']

Succede quando passiamo il dizionario per elencare (o qualsiasi altro oggetto del tipo di raccolta):

>>> list(d)
['x', 'y', 'z']

Il modo in cui Python itera è, in un contesto in cui è necessario, chiama il metodo __iter__ dell'oggetto (in questo caso il dizionario) che restituisce un iteratore (in questo caso, un oggetto keyiterator):

>>> d.__iter__()
<dict_keyiterator object at 0x7fb1747bee08>

Non dovremmo usare noi stessi questi metodi speciali, ma usare la rispettiva funzione integrata per chiamarla, iter :

>>> key_iterator = iter(d)
>>> key_iterator
<dict_keyiterator object at 0x7fb172fa9188>

Iterator hanno un metodo __next__ , ma lo chiamiamo con la funzione builtin, next :

>>> next(key_iterator)
'x'
>>> next(key_iterator)
'y'
>>> next(key_iterator)
'z'
>>> next(key_iterator)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

Quando un iteratore è esaurito, solleva StopIteration . Questo è il modo in cui Python sa di uscire da un ciclo for , o da una list list, da un'espressione di generatore o da qualsiasi altro contesto iterativo. Una volta che un iteratore solleva StopIteration lo solleverà sempre - se vuoi ripetere ancora, ne hai bisogno di uno nuovo.

>>> list(key_iterator)
[]
>>> new_key_iterator = iter(d)
>>> list(new_key_iterator)
['x', 'y', 'z']

Ritornare a dicts

Abbiamo visto i dettati che iterano in molti contesti. Quello che abbiamo visto è che ogni volta che ripetiamo un ditt, otteniamo le chiavi. Torna all'esempio originale:

d = {'x': 1, 'y': 2, 'z': 3} 
for key in d:

Se cambiamo il nome della variabile, otteniamo comunque le chiavi. Proviamolo:

>>> for each_key in d:
...     print(each_key, '=>', d[each_key])
... 
x => 1
y => 2
z => 3

Se vogliamo iterare sui valori, dobbiamo usare il metodo .values ​​di dicts, o per entrambi insieme, .items :

>>> list(d.values())
[1, 2, 3]
>>> list(d.items())
[('x', 1), ('y', 2), ('z', 3)]

Nell'esempio fornito, sarebbe più efficiente iterare sugli articoli come questo:

for a_key, corresponding_value in d.items():
    print(a_key, corresponding_value)

Ma a fini accademici, l'esempio della domanda va bene.

Sono un po 'perplesso dal seguente codice:

d = {'x': 1, 'y': 2, 'z': 3} 
for key in d:
    print key, 'corresponds to', d[key]

Quello che non capisco è la parte key . In che modo Python riconosce che è sufficiente leggere la chiave dal dizionario? La key è una parola speciale in Python? O è semplicemente una variabile?


Ho un caso d'uso in cui devo ripetere il ditt per ottenere la chiave, coppia di valori, anche l'indice che indica dove sono. Ecco come lo faccio:

d = {'x': 1, 'y': 2, 'z': 3} 
for i, (key, value) in enumerate(d.items()):
   print(i, key, value)

Si noti che le parentesi attorno alla chiave, il valore è importante, senza le parentesi, si ottiene un errore ValueError "valori insufficienti da decomprimere".


Non è che la chiave sia una parola speciale, ma quei dizionari implementano il protocollo iteratore. Puoi farlo nella tua classe, ad esempio vedi questa domanda su come costruire iteratori di classe.

Nel caso dei dizionari, è implementato a livello C. I dettagli sono disponibili in PEP 234 . In particolare, la sezione intitolata "Iterator dei dizionari":

  • I dizionari implementano uno slot tp_iter che restituisce un efficace iteratore che scorre sulle chiavi del dizionario. [...] Questo significa che possiamo scrivere

    for k in dict: ...
    

    che è equivalente a, ma molto più veloce di

    for k in dict.keys(): ...
    

    fino a quando la restrizione sulle modifiche al dizionario (sia dal loop o da un altro thread) non viene violata.

  • Aggiungi metodi ai dizionari che restituiscono esplicitamente diversi tipi di iteratori:

    for key in dict.iterkeys(): ...
    
    for value in dict.itervalues(): ...
    
    for key, value in dict.iteritems(): ...
    

    Ciò significa che for x in dict è abbreviazione for x in dict.iterkeys() .


Per iterare sui tasti, è più lento ma è meglio usare my_dict.keys() . Se hai provato a fare qualcosa di simile:

for key in my_dict:
    my_dict[key+"-1"] = my_dict[key]-1

creerebbe un errore di runtime perché stai cambiando le chiavi mentre il programma è in esecuzione. Se sei assolutamente pronto a ridurre il tempo, usa la for key in my_dict way, ma sei stato avvisato;).


Puoi verificare l'implementazione del dicttype di CPython su GitHub. Questa è la firma del metodo che implementa l'iteratore dict:

_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
             PyObject **pvalue, Py_hash_t *phash)

CPython dictobject.c


Quando si esegue l'iterazione dei dizionari usando for .. in .. -sintassi, itera sempre sulle chiavi (i valori sono accessibili usando il dictionary[key] ).

Per ripetere le coppie chiave-valore, utilizzare for k,v in s.iteritems() .


key è semplicemente una variabile.

Per Python2.X :

d = {'x': 1, 'y': 2, 'z': 3} 
for my_var in d:
    print my_var, 'corresponds to', d[my_var]

... o meglio,

d = {'x': 1, 'y': 2, 'z': 3} 
for the_key, the_value in d.iteritems():
    print the_key, 'corresponds to', the_value

Per Python3.X :

d = {'x': 1, 'y': 2, 'z': 3} 
for the_key, the_value in d.items():
    print(the_key, 'corresponds to', the_value)

key è solo un nome di variabile.

for key in d:

semplicemente passerà in rassegna i tasti nel dizionario, piuttosto che le chiavi e i valori. Per eseguire il loop su chiave e valore è possibile utilizzare quanto segue:

Per Python 2.x:

for key, value in d.iteritems():

Per Python 3.x:

for key, value in d.items():

Per testare per te stesso, cambia la parola key per poop .

Per Python 3.x, iteritems() è stato sostituito con semplicemente items() , che restituisce una vista set-like supportata dal dict, come iteritems() ma anche migliore. Questo è anche disponibile in 2.7 come viewitems() .

L'operazione items() funzionerà sia per 2 che per 3, ma in 2 restituirà un elenco delle coppie del dizionario (key, value) , che non rifletteranno le modifiche al dict che si verificano dopo la chiamata items() . Se si desidera il comportamento 2.x in 3.x, è possibile chiamare la list(d.items()) .





dictionary