先来回顾一下Python中遍历字典的一些基本方法:
脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#!/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
|
执行结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
##########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
|
嗯,然后我们进入“正题”--
一段关于Python字典遍历的“争论”....
先摘抄下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
#这里初始化一个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 }
#结果也是对的
>>>
|
其实这个问题本来很简单,就是说如果遍历一个字典,但是在遍历中改变了他,比如增删某个元素,就会导致遍历退出,并且抛出一个dictionary changed size during iteration的异常.
解决方法是遍历字典键值,以字典键值为依据遍历,这样改变了value以后不会影响遍历继续。
但是下面又有一位大神抛出高论:
首先,python 是推荐使用迭代器的,也就是 for k in adict 形式。其次,在遍历中删除容器中的元素,在 C++ STL 和 Python 等库中,都是不推荐的,因为这种情况往往说明了你的设计方案有问题,所有都有特殊要求,对应到 python 中,就是要使用 adict.key() 做一个拷贝。最后,所有的 Python 容器都不承诺线程安全,你要多线程做这件事,本身就必须得加锁,这也说明了业务代码设计有问题的.
但由“遍历中删除特定元素”这种特例,得出“遍历dict的时候,养成使用 for k in d.keys() 的习惯”,我觉得有必要纠正一下。在普通的遍历中,应该使用 for k in adict。
另外,对于“遍历中删除元素”这种需求,pythonic 的做法是 adict = {k, v for adict.iteritems() if v != 0} 或 alist = [i for i in alist if i != 0]
这个写法让我眼前一亮:怎么还有这个语法?
再仔细一看,他可能是这个意思:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#!/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
|
不知道对不对。
因为这个写法一开始让我猛然想到三元操作符,仔细一看才发现不是,以前Goolge到有个解决方案
1
2
3
4
5
6
7
|
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是个逻辑表达式,返回0或者1,刚好作为前面那个元组的ID来取值,实在是太妙了。。。
不过在Google的资料里面还有一个版本
1
2
3
4
5
|
#V1 if X else V2
s = None
a = "not null" if s = = None else s
print a
#'not null'
|
后来发帖在华蟒用户组(中文Python技术邮件列表)中提到后众多大神解答如下:
1
2
3
4
5
6
7
8
9
10
|
>>> 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
还可以用这个写法:
1
|
>>> d = {k:v for k,v in d.iteritems() if v ! = 0 }
|