Itération sur les dictionnaires à l'aide de boucles «for»

3140

Je suis un peu perplexe avec le code suivant:

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

Ce que je ne comprends pas, c'est la keyportion. Comment Python reconnaît-il qu'il suffit de lire la clé du dictionnaire? Est keyun mot spécial en Python? Ou s'agit-il simplement d'une variable?

Excellent chef
la source
4
Avant de publier une nouvelle réponse, considérez qu'il existe déjà plus de 10 réponses à cette question. Veuillez vous assurer que votre réponse fournit des informations qui ne figurent pas parmi les réponses existantes.
janniks

Réponses:

5395

key est juste un nom de variable.

for key in d:

fera simplement une boucle sur les clés du dictionnaire, plutôt que sur les clés et les valeurs. Pour parcourir la clé et la valeur, vous pouvez utiliser les éléments suivants:

Pour Python 3.x:

for key, value in d.items():

Pour Python 2.x:

for key, value in d.iteritems():

Pour tester par vous-même, remplacez le mot keypar poop.

Dans Python 3.x, a iteritems()été remplacé par simplement items(), qui retourne une vue d'ensemble définie par le dict, comme iteritems()mais encore mieux. Ceci est également disponible en 2.7 comme viewitems().

L'opération items()fonctionnera à la fois pour 2 et 3, mais en 2, elle renverra une liste des (key, value)paires du dictionnaire , qui ne reflètera pas les changements de dict qui se produisent après l' items()appel. Si vous voulez le comportement 2.x dans 3.x, vous pouvez appeler list(d.items()).

sberry
la source
158
L'ajout d'une raison ignorée pour ne pas accéder à la valeur comme ceci: d [clé] à l'intérieur de la boucle for provoque le hachage de la clé à nouveau (pour obtenir la valeur). Lorsque le dictionnaire est volumineux, ce hachage supplémentaire augmentera la durée globale. Ceci est discuté dans la conférence technique de Raymond Hettinger youtube.com/watch?v=anrOzOapJ2E
quiet_penguin
27
Il pourrait être logique de mentionner que les éléments seront itérés dans un ordre imprévisible et sortedsont nécessaires pour le stabiliser.
yugr
5
@HarisankarKrishnaSwamy quelle est l'alternative?
JoeyC
3
@yugr Pourquoi dites-vous cela? La documentation dit Keys and values are iterated over in insertion order. [ docs.python.org/3/library/…
Geza Turi
4
@yugr À partir de Python 3.7, les dictionnaires sont classés par insertion et il s'agit d'une fonction de langue. Voir stackoverflow.com/a/39980744/9428564
Aimery
433

Ce n'est pas que la clé est un mot spécial, mais que les dictionnaires implémentent le protocole itérateur. Vous pouvez le faire dans votre classe, par exemple, voyez cette question pour savoir comment construire des itérateurs de classe.

Dans le cas des dictionnaires, il est implémenté au niveau C. Les détails sont disponibles dans PEP 234 . En particulier, la section intitulée "Itérateurs de dictionnaire":

  • Les dictionnaires implémentent un emplacement tp_iter qui renvoie un itérateur efficace qui itère sur les clés du dictionnaire. [...] Cela signifie que nous pouvons écrire

    for k in dict: ...

    qui est équivalent à, mais beaucoup plus rapide que

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

    tant que la restriction sur les modifications du dictionnaire (soit par la boucle soit par un autre thread) n'est pas violée.

  • Ajoutez des méthodes aux dictionnaires qui renvoient explicitement différents types d'itérateurs:

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

    Cela signifie que for x in dictc'est un raccourci pour for x in dict.iterkeys().

En Python 3, dict.iterkeys(), dict.itervalues()et dict.iteritems()ne sont plus pris en charge. Utilisez dict.keys(), dict.values()et à la dict.items()place.

ars
la source
207

Itérer sur un dictitéré à travers ses clés dans aucun ordre particulier, comme vous pouvez le voir ici:

Edit: (Ce n'est plus le cas en Python3.6 , mais notez que ce n'est pas encore garanti )

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

Pour votre exemple, il est préférable d'utiliser dict.items():

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

Cela vous donne une liste de tuples. Lorsque vous les bouclez comme ceci, chaque tuple est décompressé ket vautomatiquement:

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

L'utilisation de ket vcomme noms de variables lors de la boucle sur un dictest assez courant si le corps de la boucle n'est que de quelques lignes. Pour les boucles plus compliquées, il peut être judicieux d'utiliser des noms plus descriptifs:

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

C'est une bonne idée de prendre l'habitude d'utiliser des chaînes de format:

for letter, number in d.items():
    print('{0} corresponds to {1}'.format(letter, number))
John La Rooy
la source
11
D'après les notes de publication de Python 3.7: "La nature de préservation de l'ordre d'insertion des objets dict fait désormais partie intégrante des spécifications du langage Python."
Gregory Arenius
86

key est simplement une variable.

Pour Python2.X :

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

... ou mieux,

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

Pour 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
la source
63

Lorsque vous parcourez les dictionnaires à l'aide de la for .. in ..syntaxe-, il itère toujours sur les clés (les valeurs sont accessibles à l'aide dictionary[key]).

Pour itérer sur des paires clé-valeur, dans Python 2, utilisez for k,v in s.iteritems()et dans Python 3 for k,v in s.items().

Alexander Gessler
la source
38
Notez que pour Python 3, c'est items()au lieu deiteritems()
Andreas Fester
19

Itération sur les dictionnaires à l'aide de boucles «for»

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

Comment Python reconnaît-il qu'il lui suffit de lire la clé du dictionnaire? La clé est-elle un mot spécial en Python? Ou s'agit-il simplement d'une variable?

Ce ne sont pas que des forboucles. Le mot important ici est "itérer".

Un dictionnaire est un mappage des clés aux valeurs:

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

Chaque fois que nous itérons dessus, nous itérons sur les touches. Le nom de la variable keyest uniquement destiné à être descriptif - et il est tout à fait approprié pour le but.

Cela se produit dans une liste de compréhension:

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

Cela se produit lorsque nous passons le dictionnaire à list (ou tout autre objet de type collection):

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

La façon dont Python itère est, dans un contexte où il le faut, il appelle la __iter__méthode de l'objet (dans ce cas le dictionnaire) qui retourne un itérateur (dans ce cas, un objet keyiterator):

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

Nous ne devrions pas utiliser ces méthodes spéciales nous-mêmes, mais utiliser la fonction intégrée respective pour l'appeler iter:

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

Itérateurs ont une __next__méthode - mais nous appelons avec la fonction 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

Lorsqu'un itérateur est épuisé, il augmente StopIteration. C'est ainsi que Python sait quitter une forboucle, ou une compréhension de liste, ou une expression de générateur, ou tout autre contexte itératif. Une fois qu'un itérateur lève, StopIterationil le relèvera toujours - si vous voulez recommencer, vous en avez besoin d'un nouveau.

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

Retour aux dict

Nous avons vu des dits itérer dans de nombreux contextes. Ce que nous avons vu, c'est que chaque fois que nous répétons un dict, nous obtenons les clés. Retour à l'exemple d'origine:

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

Si nous changeons le nom de la variable, nous obtenons toujours les clés. Essayons:

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

Si nous voulons parcourir les valeurs, nous devons utiliser la .valuesméthode des dicts, ou pour les deux ensemble .items:

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

Dans l'exemple donné, il serait plus efficace d'itérer sur les éléments comme celui-ci:

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

Mais à des fins académiques, l'exemple de la question est très bien.

Aaron Hall
la source
17

J'ai un cas d'utilisation où je dois parcourir le dict pour obtenir la clé, la paire de valeurs, ainsi que l'index indiquant où je suis. Voici comment je le fais:

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

Notez que les parenthèses autour de la clé, la valeur est importante, sans les parenthèses, vous obtenez une ValueError "pas assez de valeurs pour décompresser".

jdhao
la source
1
En quoi cela est-il pertinent pour la question?
jorijnsmit
8

Vous pouvez vérifier l'implémentation de CPython dicttypesur GitHub. C'est la signature de la méthode qui implémente l'itérateur dict:

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

CPython dictobject.c

Ankur Agarwal
la source
4

Pour parcourir les touches, il est plus lent mais préférable à utiliser my_dict.keys(). Si vous avez essayé de faire quelque chose comme ça:

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

cela créerait une erreur d'exécution car vous modifiez les clés pendant l'exécution du programme. Si vous êtes absolument déterminé à réduire le temps, utilisez le for key in my_dictchemin, mais vous avez été averti;).

Neil Chowdhury o_O
la source
2

Cela imprimera la sortie dans l'ordre trié par valeurs dans l'ordre croissant.

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)

Production:

entrez la description de l'image ici

Amar Kumar
la source