Maison > Article > développement back-end > La modification d'éléments lors de la traversée du dictionnaire en Python provoque des exceptions
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
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
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 {'a': 1, 'c': 1, 'd': 0} >>> d = {'a':1, 'b':0, 'c':1, 'd':0} #d.keys() 是一个下标的数组 >>> d.keys() ['a', 'c', 'b', 'd'] #这样遍历,就没问题了,因为其实其实这里遍历的是d.keys()这个list常量。 >>> for k in d.keys(): ... if d[k] == 0: ... del(d[k]) ... >>> d {'a': 1, 'c': 1} #结果也是对的 >>> #这里初始化一个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 {'a': 1, 'c': 1, 'd': 0} >>> d = {'a':1, 'b':0, 'c':1, 'd':0} #d.keys() 是一个下标的数组 >>> d.keys() ['a', 'c', 'b', 'd'] #这样遍历,就没问题了,因为其实其实这里遍历的是d.keys()这个list常量。 >>> for k in d.keys(): ... if d[k] == 0: ... del(d[k]) ... >>> d {'a': 1, 'c': 1} #结果也是对的 >>>
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 = {'a':1, 'b':0, 'c':1, 'd':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 = {'a':1, 'b':0, 'c':1, 'd':0} b={} for k,v in a.items(): if v != 0: b.update({k:v}) adict = b del b print a
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",statusval>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 #'not null'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 = {'a':1, 'b':0, 'c':1, 'd':0} >>> d = dict([(k,v) for k,v in d.iteritems() if v!=0]) >>> d {'a':1,'c':1'}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 }