Python中遍歷字典過程中更改元素導(dǎo)致異常的解決方法
先來回顧一下Python中遍歷字典的一些基本方法:
腳本:
#!/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
執(zhí)行結(jié)果:
##########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
嗯,然后我們進(jìn)入“正題”--
一段關(guān)于Python字典遍歷的“爭(zhēng)論”....
先摘抄下:
#這里初始化一個(gè)dict
>>> d = {'a':1, 'b':0, 'c':1, 'd':0}
#本意是遍歷dict,發(fā)現(xiàn)元素的值是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
#結(jié)果拋出異常了,兩個(gè)0的元素,也只刪掉一個(gè)。
>>> d
{'a': 1, 'c': 1, 'd': 0}
>>> d = {'a':1, 'b':0, 'c':1, 'd':0}
#d.keys() 是一個(gè)下標(biāo)的數(shù)組
>>> d.keys()
['a', 'c', 'b', 'd']
#這樣遍歷,就沒問題了,因?yàn)槠鋵?shí)其實(shí)這里遍歷的是d.keys()這個(gè)list常量。
>>> for k in d.keys():
... if d[k] == 0:
... del(d[k])
...
>>> d
{'a': 1, 'c': 1}
#結(jié)果也是對(duì)的
>>>
#這里初始化一個(gè)dict
>>> d = {'a':1, 'b':0, 'c':1, 'd':0}
#本意是遍歷dict,發(fā)現(xiàn)元素的值是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
#結(jié)果拋出異常了,兩個(gè)0的元素,也只刪掉一個(gè)。
>>> d
{'a': 1, 'c': 1, 'd': 0}
>>> d = {'a':1, 'b':0, 'c':1, 'd':0}
#d.keys() 是一個(gè)下標(biāo)的數(shù)組
>>> d.keys()
['a', 'c', 'b', 'd']
#這樣遍歷,就沒問題了,因?yàn)槠鋵?shí)其實(shí)這里遍歷的是d.keys()這個(gè)list常量。
>>> for k in d.keys():
... if d[k] == 0:
... del(d[k])
...
>>> d
{'a': 1, 'c': 1}
#結(jié)果也是對(duì)的
>>>
其實(shí)這個(gè)問題本來很簡(jiǎn)單,就是說如果遍歷一個(gè)字典,但是在遍歷中改變了他,比如增刪某個(gè)元素,就會(huì)導(dǎo)致遍歷退出,并且拋出一個(gè)dictionary changed size during iteration的異常.
解決方法是遍歷字典鍵值,以字典鍵值為依據(jù)遍歷,這樣改變了value以后不會(huì)影響遍歷繼續(xù)。
但是下面又有一位大神拋出高論:
首先,python 是推薦使用迭代器的,也就是 for k in adict 形式。其次,在遍歷中刪除容器中的元素,在 C++ STL 和 Python 等庫中,都是不推薦的,因?yàn)檫@種情況往往說明了你的設(shè)計(jì)方案有問題,所有都有特殊要求,對(duì)應(yīng)到 python 中,就是要使用 adict.key() 做一個(gè)拷貝。最后,所有的 Python 容器都不承諾線程安全,你要多線程做這件事,本身就必須得加鎖,這也說明了業(yè)務(wù)代碼設(shè)計(jì)有問題的.
但由“遍歷中刪除特定元素”這種特例,得出“遍歷dict的時(shí)候,養(yǎng)成使用 for k in d.keys() 的習(xí)慣”,我覺得有必要糾正一下。在普通的遍歷中,應(yīng)該使用 for k in adict。
另外,對(duì)于“遍歷中刪除元素”這種需求,pythonic 的做法是 adict = {k, v for adict.iteritems() if v != 0} 或 alist = [i for i in alist if i != 0]
這個(gè)寫法讓我眼前一亮:怎么還有這個(gè)語法?
再仔細(xì)一看,他可能是這個(gè)意思:
#!/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
不知道對(duì)不對(duì)。
因?yàn)檫@個(gè)寫法一開始讓我猛然想到三元操作符,仔細(xì)一看才發(fā)現(xiàn)不是,以前Goolge到有個(gè)解決方案
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
val>65是個(gè)邏輯表達(dá)式,返回0或者1,剛好作為前面那個(gè)元組的ID來取值,實(shí)在是太妙了。。。
不過在Google的資料里面還有一個(gè)版本
#V1 if X else V2 s = None a = "not null" if s == None else s print a #'not null'
后來發(fā)帖在華蟒用戶組(中文Python技術(shù)郵件列表)中提到后眾多大神解答如下:
>>> 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'}
如果大于Python>=2.7
還可以用這個(gè)寫法:
>>> d = {k:v for k,v in d.iteritems() if v !=0 }
相關(guān)文章
Python操作Mysql實(shí)例代碼教程在線版(查詢手冊(cè))
本文介紹了Python操作MYSQL、執(zhí)行SQL語句、獲取結(jié)果集、遍歷結(jié)果集、取得某個(gè)字段、獲取表字段名、將圖片插入數(shù)據(jù)庫、執(zhí)行事務(wù)等各種代碼實(shí)例和詳細(xì)介紹,代碼居多,是一桌豐盛唯美的代碼大餐2013-02-02
Python實(shí)現(xiàn)Event回調(diào)機(jī)制的方法
今天小編就為大家分享一篇Python實(shí)現(xiàn)Event回調(diào)機(jī)制的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-02-02
python簡(jiǎn)單實(shí)現(xiàn)刷新智聯(lián)簡(jiǎn)歷
本文給大家分享的是個(gè)人弄的一個(gè)使用Python簡(jiǎn)單實(shí)現(xiàn)刷新智聯(lián)招聘簡(jiǎn)歷的小工具的代碼,非常的簡(jiǎn)單,給大家參考下吧。2016-03-03
完美解決Python matplotlib繪圖時(shí)漢字顯示不正常的問題
今天小編就為大家分享一篇完美解決Python matplotlib繪圖時(shí)漢字顯示不正常的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01
Python設(shè)置Word頁面紙張方向?yàn)闄M向
這篇文章主要為大家詳細(xì)介紹了Python設(shè)置Word頁面紙張方向?yàn)闄M向的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起2024-02-02
Python使用設(shè)計(jì)模式中的責(zé)任鏈模式與迭代器模式的示例
這篇文章主要介紹了Python使用設(shè)計(jì)模式中的責(zé)任鏈模式與迭代器模式的示例,責(zé)任鏈模式與迭代器模式都可以被看作為行為型的設(shè)計(jì)模式,需要的朋友可以參考下2016-03-03

