Iterando sobre diccionarios usando bucles 'for'

3139

Estoy un poco desconcertado por el siguiente código:

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

Lo que no entiendo es la keyporción. ¿Cómo reconoce Python que solo necesita leer la clave del diccionario? ¿Es keyuna palabra especial en Python? ¿O es simplemente una variable?

El mejor chef
fuente
44
Antes de publicar una nueva respuesta, considere que ya hay más de 10 respuestas para esta pregunta. Por favor, asegúrese de que su respuesta contribuya con información que no se encuentre entre las respuestas existentes.
Janniks

Respuestas:

5394

key es solo un nombre de variable.

for key in d:

simplemente recorrerá las claves del diccionario, en lugar de las claves y los valores. Para recorrer tanto la clave como el valor, puede usar lo siguiente:

Para Python 3.x:

for key, value in d.items():

Para Python 2.x:

for key, value in d.iteritems():

Para probarlo usted mismo, cambie la palabra keya poop.

En Python 3.x, iteritems()se reemplazó con simplemente items(), que devuelve una vista de conjunto respaldada por el dict, iteritems()pero aún mejor. Esto también está disponible en 2.7 como viewitems().

La operación items()funcionará para 2 y 3, pero en 2 devolverá una lista de los (key, value)pares del diccionario , que no reflejará los cambios en el dict que suceden después de la items()llamada. Si desea el comportamiento 2.x en 3.x, puede llamar list(d.items()).

fresa
fuente
158
Agregar una razón pasada por alto para no acceder a un valor como este: d [clave] dentro del bucle for hace que la clave se vuelva a cifrar (para obtener el valor). Cuando el diccionario es grande, este hash adicional se agregará al tiempo total. Esto se discute en la charla técnica de Raymond Hettinger youtube.com/watch?v=anrOzOapJ2E
quiet_penguin
27
Podría tener sentido mencionar que los elementos se iterarán en un orden impredecible y sortedson necesarios para estabilizarlo.
yugr
55
@HarisankarKrishnaSwamy ¿cuál es la alternativa?
JoeyC
3
@yugr ¿Por qué dices eso? Los documentos dicen Keys and values are iterated over in insertion order. [ docs.python.org/3/library/…
Geza Turi
44
@yugr Desde Python 3.7, los diccionarios están ordenados por inserción y esta es una característica del lenguaje. Ver stackoverflow.com/a/39980744/9428564
Aimery el
433

No es que la clave sea una palabra especial, sino que los diccionarios implementan el protocolo iterador. Puede hacer esto en su clase, por ejemplo, vea esta pregunta sobre cómo construir iteradores de clase.

En el caso de los diccionarios, se implementa en el nivel C. Los detalles están disponibles en PEP 234 . En particular, la sección titulada "Iteradores de diccionario":

  • Los diccionarios implementan una ranura tp_iter que devuelve un iterador eficiente que itera sobre las teclas del diccionario. [...] Esto significa que podemos escribir

    for k in dict: ...

    que es equivalente a, pero mucho más rápido que

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

    siempre que no se infrinja la restricción de modificaciones al diccionario (ya sea por el bucle o por otro hilo).

  • Agregue métodos a los diccionarios que devuelven diferentes tipos de iteradores explícitamente:

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

    Esto significa que for x in dictes la abreviatura de for x in dict.iterkeys().

En Python 3, dict.iterkeys(), dict.itervalues()y dict.iteritems()ya no son compatibles. Uso dict.keys(), dict.values()y en su dict.items()lugar.

ars
fuente
207

Iterar sobre un dictitera a través de sus teclas en ningún orden particular, como puede ver aquí:

Editar: (Este ya no es el caso en Python3.6 , pero tenga en cuenta que todavía no se garantiza el comportamiento)

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

Para su ejemplo, es una mejor idea usar dict.items():

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

Esto te da una lista de tuplas. Cuando los recorres así, cada tupla se desempaqueta ky vautomáticamente:

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

Usar ky vcomo nombres de variables cuando se repite en un bucle dictes bastante común si el cuerpo del bucle tiene solo unas pocas líneas. Para bucles más complicados, puede ser una buena idea usar nombres más descriptivos:

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

Es una buena idea acostumbrarse a usar cadenas de formato:

for letter, number in d.items():
    print('{0} corresponds to {1}'.format(letter, number))
John La Rooy
fuente
11
De las notas de la versión Python 3.7: "La naturaleza de preservación del orden de inserción de los objetos dict ahora es una parte oficial de la especificación del lenguaje Python".
Gregory Arenius
86

key Es simplemente una variable.

Para Python2.X :

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

... o mejor,

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

Para Python3.X :

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

Cuando itera a través de diccionarios usando la for .. in ..sintaxis, siempre itera sobre las claves (se puede acceder a los valores usando dictionary[key]).

Para iterar sobre pares clave-valor, en Python 2 use for k,v in s.iteritems()y en Python 3 for k,v in s.items().

Alexander Gessler
fuente
38
Tenga en cuenta que para Python 3, es en items()lugar deiteritems()
Andreas Fester
19

Iterando sobre diccionarios usando bucles 'for'

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

¿Cómo reconoce Python que solo necesita leer la clave del diccionario? ¿Es clave una palabra especial en Python? ¿O es simplemente una variable?

No son solo forbucles. La palabra importante aquí es "iterar".

Un diccionario es un mapeo de claves a valores:

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

Cada vez que iteramos sobre él, iteramos sobre las teclas. El nombre de la variable keysolo pretende ser descriptivo, y es bastante apto para este propósito.

Esto sucede en una lista de comprensión:

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

Sucede cuando pasamos el diccionario a la lista (o cualquier otro objeto de tipo de colección):

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

La forma en que Python itera es, en un contexto donde lo necesita, llama al __iter__método del objeto (en este caso, el diccionario) que devuelve un iterador (en este caso, un objeto keyiterator):

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

No deberíamos usar estos métodos especiales nosotros mismos, en su lugar, use la función incorporada respectiva para llamarlo iter:

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

Los iteradores tienen un __next__método, pero lo llamamos con la función integrada 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

Cuando un iterador se agota, se eleva StopIteration. Así es como Python sabe salir de un forbucle, o una comprensión de la lista, o una expresión generadora, o cualquier otro contexto iterativo. Una vez StopIterationque se eleva un iterador , siempre lo elevará; si desea repetir nuevamente, necesita uno nuevo.

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

Volviendo a los dictados

Hemos visto dictados iterando en muchos contextos. Lo que hemos visto es que cada vez que iteramos sobre un dict, obtenemos las claves. Regresando al ejemplo original:

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

Si cambiamos el nombre de la variable, aún obtenemos las claves. Vamos a intentarlo:

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

Si queremos iterar sobre los valores, necesitamos usar el .valuesmétodo de dictados, o para ambos juntos .items:

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

En el ejemplo dado, sería más eficiente iterar sobre los elementos como este:

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

Pero para fines académicos, el ejemplo de la pregunta está bien.

Aaron Hall
fuente
17

Tengo un caso de uso en el que tengo que recorrer el dict para obtener la clave, el par de valores, también el índice que indica dónde estoy. Así es como lo hago:

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

Tenga en cuenta que los paréntesis alrededor de la clave, el valor es importante, sin los paréntesis, obtendrá un ValueError "no hay suficientes valores para desempaquetar".

jdhao
fuente
1
¿Cómo es esto relevante para la pregunta?
jorijnsmit
8

Puede verificar la implementación de CPython dicttypeen GitHub. Esta es la firma del método que implementa el iterador dict:

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

CPython dictobject.c

Ankur Agarwal
fuente
4

Para iterar sobre las teclas, es más lento pero mejor usarlo my_dict.keys(). Si trataste de hacer algo como esto:

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

crearía un error de tiempo de ejecución porque está cambiando las claves mientras se ejecuta el programa. Si está absolutamente decidido a reducir el tiempo, utilice el for key in my_dictcamino, pero se le ha advertido;).

Neil Chowdhury o_O
fuente
2

Esto imprimirá la salida en orden ordenado por valores en orden ascendente.

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)

Salida:

ingrese la descripción de la imagen aquí

Amar Kumar
fuente