Scorrere i dizionari usando i cicli 'for'


3139

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 keyporzione. In che modo Python riconosce che deve solo leggere la chiave dal dizionario? È keyuna parola speciale in Python? O è semplicemente una variabile?


4
Prima di pubblicare una nuova risposta, considera che ci sono già più di 10 risposte per questa domanda. Assicurati che la tua risposta fornisca informazioni che non sono tra le risposte esistenti.
Janniks,

Risposte:


5394

key è solo un nome variabile.

for key in d:

passerà semplicemente sopra le chiavi del dizionario, piuttosto che le chiavi e i valori. Per scorrere sia la chiave che il valore è possibile utilizzare quanto segue:

Per Python 3.x:

for key, value in d.items():

Per Python 2.x:

for key, value in d.iteritems():

Per testare te stesso, cambia la parola keyin poop.

In Python 3.x, è iteritems()stato sostituito con semplicemente items(), che restituisce una vista simile a un set supportata dal dict, come iteritems()ma anche meglio. Questo è disponibile anche in 2.7 come viewitems().

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


158
Aggiungendo un motivo trascurato per non accedere al valore in questo modo: d [chiave] all'interno del ciclo for fa sì che la chiave venga nuovamente hash (per ottenere il valore). Quando il dizionario è di grandi dimensioni, questo hash extra aumenterà il tempo complessivo. Questo è discusso nel discorso tecnico di Raymond Hettinger su youtube.com/watch?v=anrOzOapJ2E
quiet_penguin,

27
Potrebbe avere senso menzionare che gli articoli verranno ripetuti in un ordine imprevedibile ed sortedè necessario per stabilizzarli.
yugr

5
@HarisankarKrishnaSwamy qual è l'alternativa?
JoeyC

3
@yugr Perché dici questo? I documenti dicono Keys and values are iterated over in insertion order. [ docs.python.org/3/library/…
Geza Turi,

4
@yugr Da Python 3.7, i dizionari sono ordinati per inserzione e questa è una funzione linguistica. Vedi stackoverflow.com/a/39980744/9428564
Aimery

433

Non è quella chiave una parola speciale, ma i dizionari implementano il protocollo iteratore. Potresti 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 "Dizionario Iteratori":

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

    for k in dict: ...

    che è equivalente a, ma molto più veloce di

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

    fintanto che la restrizione alle modifiche al dizionario (tramite il ciclo 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(): ...

    Questo significa che for x in dictè una scorciatoia per for x in dict.iterkeys().

In Python 3, dict.iterkeys(), dict.itervalues()e dict.iteritems()non sono più supportati. Usa dict.keys(), dict.values()e dict.items()invece.


207

Scorrere su dictun'iterazione attraverso le sue chiavi in ​​nessun ordine particolare, come puoi vedere qui:

Modifica: (Questo non è più il caso in Python3.6 , ma nota che non è ancora garantito il comportamento)

>>> d = {'x': 1, 'y': 2, 'z': 3} 
>>> list(d)
['y', 'x', 'z']
>>> d.keys()
['y', 'x', 'z']

Per il tuo esempio, è una migliore idea usare dict.items():

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

Questo ti dà un elenco di tuple. Quando li attraversi in questo modo, ogni tupla viene scompattata ke vautomaticamente:

for k,v in d.items():
    print(k, 'corresponds to', v)

L'uso di ke vcome nomi di variabili durante il loop su a dictè abbastanza comune se il corpo del loop è solo di poche righe. Per loop più complicati può essere una buona idea usare nomi più descrittivi:

for letter, number in d.items():
    print(letter, 'corresponds to', number)

È una buona idea prendere l'abitudine di utilizzare le stringhe di formato:

for letter, number in d.items():
    print('{0} corresponds to {1}'.format(letter, number))

11
Dalle note di rilascio di Python 3.7: "La natura di conservazione dell'ordine di inserimento degli oggetti dict è ora una parte ufficiale delle specifiche del linguaggio Python."
Gregory Arenius,

86

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)

63

Quando si scorre i dizionari usando la for .. in ..sintassi -serta, scorre sempre sulle chiavi (i valori sono accessibili usando dictionary[key]).

Per scorrere le coppie chiave-valore, in Python 2 usa for k,v in s.iteritems()e in Python 3 for k,v in s.items().


38
Nota che per Python 3 è items()invece diiteritems()
Andreas Fester


19

Scorrere i dizionari usando i cicli 'for'

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

In che modo Python riconosce che deve solo leggere la chiave dal dizionario? Chiave è una parola speciale in Python? O è semplicemente una variabile?

Non sono solo forloop. La parola importante qui è "iterare".

Un dizionario è una mappatura delle chiavi ai valori:

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

Ogni volta che ripetiamo, ripetiamo le chiavi. Il nome della variabile keydeve essere solo descrittivo - ed è abbastanza adatto allo scopo.

Questo accade nella comprensione di un elenco:

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

Succede quando passiamo il dizionario all'elenco (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 __iter__metodo 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 questi metodi speciali noi stessi, invece, utilizzare la rispettiva funzione integrata per chiamarla iter:

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

Gli iteratori hanno un __next__metodo, ma lo chiamiamo con la funzione integrata 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, si alza StopIteration. Questo è il modo in cui Python sa uscire da un forciclo, da una comprensione di elenco, da un'espressione di un generatore o da qualsiasi altro contesto iterativo. Una volta che un iteratore si alza StopIteration, lo solleverà sempre - se vuoi iterare di nuovo, ne hai bisogno di uno nuovo.

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

Tornando a dadi

Abbiamo visto dicts iterare in molti contesti. Quello che abbiamo visto è che ogni volta che ripetiamo un dict, 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 ancora le chiavi. Proviamolo:

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

Se vogliamo iterare i valori, dobbiamo usare il .valuesmetodo 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 scorrere gli elementi in questo modo:

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

Ma per scopi accademici, l'esempio della domanda va bene.


17

Ho un caso d'uso in cui devo scorrere il dict per ottenere la chiave, la 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 tra parentesi attorno alla chiave, value è importante, senza parentesi si ottiene un ValueError "valori non sufficienti per decomprimere".


1
In che modo ciò è rilevante per la domanda?
jorijnsmit,

8

Puoi controllare l'implementazione di CPython dicttypesu 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


4

Per scorrere i tasti, è più lento ma è meglio usarlo my_dict.keys(). Se hai provato a fare qualcosa del genere:

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 intenzionato a ridurre i tempi, usa la for key in my_dictstrada, ma sei stato avvisato;).


2

Ciò stamperà l'output in ordine ordinato per Valori in ordine crescente.

d = {'x': 3, 'y': 1, 'z': 2}
def by_value(item):
    return item[1]

for key, value in sorted(d.items(), key=by_value):
    print(key, '->', value)

Produzione:

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.