Itération sur dictionnaires utilisant des boucles "pour"

je suis un peu perplexe par 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 partie key . Comment Python reconnaître qu'il n'a besoin que de lire les clés du dictionnaire? Est-ce que key est un mot spécial en Python? Ou est-ce simplement une variable?

2225
demandé sur sberry 2010-07-21 02:27:42

11 réponses

key est juste un nom de variable.

for key in d:

en boucle sur les touches dans le dictionnaire, plutôt que les clés et les valeurs. Pour passer en boucle à la fois la clé et la valeur, vous pouvez utiliser ce qui suit:

Pour Python 2.x:

for key, value in d.iteritems():

Pour Python 3.x:

for key, value in d.items():

pour tester par vous-même, changez le mot key en poop .

pour Python 3.x, iteritems() a été remplacé par simplement items() , qui renvoie une vue en set-like soutenue par le dict, comme iteritems() mais encore mieux. Ceci est également disponible en 2.7 comme viewitems() .

L'opération items() fonctionne pour les 2 et 3, mais dans le 2 il sera de retour une liste du dictionnaire (key, value) paires, ce qui ne sera pas refléter les changements apportés à la dict que se passera après la items() appel. Si vous voulez le 2.x comportement en 3.x, vous pouvez appelez list(d.items()) .

4007
répondu sberry 2018-05-17 06:27:24

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

dans le cas des dictionnaires, il est mis en œuvre au niveau C. Les détails sont disponibles dans PEP 234 . En particulier, la section intitulée "Dictionary Iterators":

  • Les dictionnaires

    implémentent un slot tp_iter qui retourne un itérateur qui itère sur les touches du dictionnaire. [...] Ce signifie que nous pouvons écrire

    for k in dict: ...
    

    qui est équivalent à, mais beaucoup plus rapide que

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

    aussi longtemps que la restriction sur les modifications au dictionnaire (soit par la boucle ou par un autre thread) ne sont pas violés.

  • ajouter méthodes de dictionnaires qui renvoient différents types de itérateurs explicitement:

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

    signifie que for x in dict signifie for x in dict.iterkeys() .

334
répondu ars 2017-05-23 10:31:37

itérant sur un dict itère à travers ses clés dans aucun ordre particulier, comme vous pouvez le voir ici:

Edit: (C'est n'est plus le cas dans Python3.6 , mais note que c'est pas de garantie comportement encore)

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

Pour ton exemple, c'est une meilleure idée d'utiliser dict.items() :

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

Cela vous donne une liste de tuples. Lorsque vous bouclez au-dessus d'eux comme ceci, chaque tuple est déballé dans k et v automatiquement:

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

en utilisant k et v comme noms variables lors d'une boucle au-dessus d'un dict est assez commun si le corps de la boucle est seulement 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 le format cordes:

for letter, number in d.items():
    print('{0} corresponds to {1}'.format(letter, number))
158
répondu John La Rooy 2017-10-31 15:12:04

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)
54
répondu ssoler 2018-06-15 10:51:39

lorsque vous itérez les dictionnaires en utilisant la syntaxe for .. in .. , il itère toujours sur les touches (les valeurs sont accessibles en utilisant dictionary[key] ).

pour itérer sur des paires de valeurs clés, utilisez for k,v in s.iteritems() .

40
répondu Alexander Gessler 2010-07-20 22:29:15

c'est un idiome très courant. in est un opérateur. Pour savoir quand utiliser for key in dict et quand il doit être for key in dict.keys() voir article de Python idiomatique de David Goodger .

20
répondu chryss 2010-07-20 22:42:58

vous pouvez utiliser ceci:

for key,val in d.items():
    print key, 'is the key for ', val
9
répondu A H M Forhadul Islam 2017-03-04 21:47:32

j'ai un cas d'utilisation où je dois itérer à travers le dict pour obtenir la clé, paire de valeur, aussi l'indice indiquant où je suis. C'est comme ça que 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é, valeur est important, sans les parenthèses, vous obtenez une Valeurerror "pas assez de valeurs à déballer".

7
répondu jdhao 2017-06-02 15:37:54

Itération sur les dictionnaires de l'aide "pour" boucles

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

comment Python reconnaît-il qu'il n'a besoin que de lire la clé dictionnaire? Est-ce que key est un mot spécial en Python? Ou est-ce simplement un variable?

ce n'est pas juste for boucles. Le mot important ici est "itération".

un dictionnaire est un mapping de clés à des valeurs:

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

chaque fois que nous itérons sur elle, nous itérons sur les clés. Le nom de la variable key se veut seulement descriptif - et il est tout à fait approprié à cette fin.

cela se produit dans une liste de compréhension:

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

il arrive quand nous passons le dictionnaire à la liste (ou tout autre objet de type collection):

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

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

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

nous ne devrions pas utiliser ces méthodes spéciales nous-mêmes, à la place, 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 l'appelons avec la fonction intégrée, 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 soulève StopIteration . C'est ainsi que Python sait sortir d'une boucle for , ou d'une compréhension de liste, ou d'une expression de générateur, ou de tout autre contexte itératif. Une fois qu'un itérateur soulève StopIteration , il le soulève toujours - si vous voulez itérer à nouveau, vous avez besoin d'un nouveau.

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

Retour à dicts

nous avons vu des dicts itérer dans de nombreux contextes. Ce que nous avons vu, c'est que chaque fois que nous itérons sur un dict, nous avons la remise des clés. Retour à l'exemple original:

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 itérer sur les valeurs, nous devons utiliser la méthode .values de 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 ceci:

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.

5
répondu Aaron Hall 2017-06-21 02:51:51

vous pouvez vérifier l'implémentation du dicttype de CPython sur 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)

Disponible dictobject.c

3
répondu abc 2018-05-19 18:38:01

pour itérer sur les touches, il est plus lent mais préférable d'utiliser my_dict.keys() . Si vous avez essayé de faire quelque chose comme ceci:

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

cela créerait une erreur d'exécution parce que vous changez les clés pendant que le programme est en cours d'exécution. Si vous êtes absolument fixé sur la réduction, utilisez le for key in my_dict , mais vous avez été averti ;).

0
répondu Neil Chowdhury o_O 2015-12-31 18:39:18