La modification d'éléments lors de la traversée du dictionnaire en Python provoque des exceptions

高洛峰
Libérer: 2017-03-02 16:49:24
original
1113 Les gens l'ont consulté

Tout d'abord, passons en revue quelques méthodes de base pour parcourir les dictionnaires en Python :

Script :

#!/usr/bin/python 
dict={"a":"apple","b":"banana","o":"orange"} 
 
print "##########dict######################" 
for i in dict: 
    print "dict[%s]=" % i,dict[i] 
 
print "###########items#####################" 
for (k,v) in dict.items(): 
    print "dict[%s]=" % k,v 
 
print "###########iteritems#################" 
for k,v in dict.iteritems(): 
    print "dict[%s]=" % k,v 
 
print "###########iterkeys,itervalues#######" 
for k,v in zip(dict.iterkeys(),dict.itervalues()): 
    print "dict[%s]=" % k,v
Copier après la connexion

Résultats de l'exécution :

##########dict###################### 
dict[a]= apple 
dict[b]= banana 
dict[o]= orange 
###########items##################### 
dict[a]= apple 
dict[b]= banana 
dict[o]= orange 
###########iteritems################# 
dict[a]= apple 
dict[b]= banana 
dict[o]= orange 
###########iterkeys,itervalues####### 
dict[a]= apple 
dict[b]= banana 
dict[o]= orange
Copier après la connexion

Eh bien, nous arrivons au "sujet principal"--

Un paragraphe sur Python Le "débat" sur la traversée du dictionnaire....
Extrait en premier :

#这里初始化一个dict
>>> d = {'a':1, 'b':0, 'c':1, 'd':0}
#本意是遍历dict,发现元素的值是0的话,就删掉
>>> for k in d:
...  if d[k] == 0:
...   del(d[k])
...
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
#结果抛出异常了,两个0的元素,也只删掉一个。
>>> d
{&#39;a&#39;: 1, &#39;c&#39;: 1, &#39;d&#39;: 0}

>>> d = {&#39;a&#39;:1, &#39;b&#39;:0, &#39;c&#39;:1, &#39;d&#39;:0}
#d.keys() 是一个下标的数组
>>> d.keys()
[&#39;a&#39;, &#39;c&#39;, &#39;b&#39;, &#39;d&#39;]
#这样遍历,就没问题了,因为其实其实这里遍历的是d.keys()这个list常量。
>>> for k in d.keys():
...  if d[k] == 0:
...   del(d[k])
...
>>> d
{&#39;a&#39;: 1, &#39;c&#39;: 1}
#结果也是对的
>>>

#这里初始化一个dict
>>> d = {&#39;a&#39;:1, &#39;b&#39;:0, &#39;c&#39;:1, &#39;d&#39;:0}
#本意是遍历dict,发现元素的值是0的话,就删掉
>>> for k in d:
...  if d[k] == 0:
...   del(d[k])
...
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
#结果抛出异常了,两个0的元素,也只删掉一个。
>>> d
{&#39;a&#39;: 1, &#39;c&#39;: 1, &#39;d&#39;: 0}
 
>>> d = {&#39;a&#39;:1, &#39;b&#39;:0, &#39;c&#39;:1, &#39;d&#39;:0}
#d.keys() 是一个下标的数组
>>> d.keys()
[&#39;a&#39;, &#39;c&#39;, &#39;b&#39;, &#39;d&#39;]
#这样遍历,就没问题了,因为其实其实这里遍历的是d.keys()这个list常量。
>>> for k in d.keys():
...  if d[k] == 0:
...   del(d[k])
...
>>> d
{&#39;a&#39;: 1, &#39;c&#39;: 1}
#结果也是对的
>>>
Copier après la connexion

En fait, ce problème est très simple, c'est-à-dire que si un dictionnaire est parcouru, mais qu'il est modifié pendant le parcours, comme l'ajout ou la suppression d'un élément, le parcours se terminera et une exception de taille modifiée du dictionnaire au cours de l'itération sera levée.
Le La solution consiste à parcourir les valeurs clés du dictionnaire et à utiliser le dictionnaire. Le parcours est basé sur la valeur clé, donc changer la valeur n'affectera pas la suite du parcours.
Mais voici un autre grand expert qui a donné une haute opinion :

Tout d'abord, python recommande d'utiliser des itérateurs, c'est-à-dire for k sous forme adict. Deuxièmement, la suppression d'éléments dans le conteneur pendant le parcours n'est pas recommandée dans des bibliothèques telles que C STL et Python, car cette situation indique souvent qu'il y a un problème avec votre plan de conception, et toutes ont des exigences particulières, qui correspondent à python , utilisez simplement. adict.key() pour faire une copie. Enfin, tous les conteneurs Python ne promettent pas la sécurité des threads. Si vous souhaitez faire cela avec plusieurs threads, vous devez le verrouiller. Cela montre également qu'il y a un problème avec la conception du code métier.

Mais à cause du. "traversement" Dans le cas particulier de "supprimer des éléments spécifiques", je suis arrivé à la conclusion que "lors du parcours de dict, prenez l'habitude d'utiliser for k dans d.keys()", je pense qu'il est nécessaire de le corriger. Dans un parcours ordinaire, vous devez utiliser for k dans adict.
De plus, pour l'exigence de "supprimer des éléments pendant le parcours", l'approche pythonique est adict = {k, v for adict.iteritems() if v != 0} ou alist = [i for i in alist if i ! = 0]

Cette façon d'écrire m'a fait briller les yeux : Pourquoi y a-t-il encore cette syntaxe ?
En regardant attentivement, il pourrait vouloir dire ceci :

#!/usr/bin/env python
# -*- coding=utf-8 -*-
a = {&#39;a&#39;:1, &#39;b&#39;:0, &#39;c&#39;:1, &#39;d&#39;:0}
b={}
for k,v in a.items():
  if v != 0:
    b.update({k:v})
adict = b
del b
print a

#!/usr/bin/env python
# -*- coding=utf-8 -*-
a = {&#39;a&#39;:1, &#39;b&#39;:0, &#39;c&#39;:1, &#39;d&#39;:0}
b={}
for k,v in a.items():
  if v != 0:
    b.update({k:v})
adict = b
del b
print a
Copier après la connexion

Je ne sais pas si c’est vrai.
Parce que cette façon d'écrire m'a tout d'un coup fait penser à l'opérateur ternaire au début. Après y avoir regardé de plus près, je me suis rendu compte que ce n'était pas le cas dans Google avant

<. 🎜>
val = float(raw_input("Age: "))
status = ("working","retired")[val>65]
print "You should be",status

val = float(raw_input("Age: "))
status = ("working","retired")[val>65]
print "You should be",status
Copier après la connexion

val>65 est une expression logique, renvoyant 0 ou 1, qui se trouve être l'ID du tuple précédent, ce qui est vraiment merveilleux. . .

Cependant, il existe également une version dans les informations de Google

#V1 if X else V2
s = None
a = "not null" if s == None else s
print a
#&#39;not null&#39;
Copier après la connexion

Plus tard, un message a été publié dans le groupe d'utilisateurs Huanang (mailing technique Python chinois liste) Après leur arrivée, de nombreux experts ont répondu comme suit :


>>> alist = [1,2,0,3,0,4,5]
>>> alist = [i for i in alist if i != 0]
>>> alist

[1, 2, 3, 4, 5]

>>> d = {&#39;a&#39;:1, &#39;b&#39;:0, &#39;c&#39;:1, &#39;d&#39;:0}
>>> d = dict([(k,v) for k,v in d.iteritems() if v!=0])
>>> d
{&#39;a&#39;:1,&#39;c&#39;:1&#39;}
Copier après la connexion

S'il est plus grand que Python>=2.7

, vous pouvez utilisez également cette écriture :

>>> d = {k:v for k,v in d.iteritems() if v !=0 }
Copier après la connexion


Pour plus d'articles connexes sur les exceptions causées par la modification d'éléments lors de la traversée du dictionnaire en Python , veuillez faire attention au site Web PHP chinois !


Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!