Python list dict iteration

本文介绍Python中高效遍历list和dict的方法,包括使用enumerate获取索引值和利用dict的iteritems及viewitems方法进行键值对遍历。

Python tricks(3) -- list和dict的遍历和方法

2014-01-23 23:11 by 会被淹死的鱼, 1631 阅读, 0 评论, 收藏,  编辑

每个人在使用python的过程中都会遍历list和dict.

List遍历

最常用最简单的遍历list的方法

1
2
3
4
5
=  [ "a" "b" "c" "d" ]
 
# simple iterate
for  in  a:
     print  i

但是, 如果我需要拿到list的index, 很多人可能会这样写

1
2
3
4
5
=  [ "a" "b" "c" "d" ]
 
# index & value
for  in  xrange ( len (a)):
     print  i, a[i]

其实, python提供了一个方法enumerate, 用法如下

1
2
3
4
5
=  [ "a" "b" "c" "d" ]
 
# iterate with index
for  i, el  in  enumerate (a):
     print  i, el

上面两种方式的结果相同

1
2
3
4
0  a
1  b
2  c
3  d

这是一种更加方便便捷的方式, 虽然少写不了几个字符, 从代码可读性等方面来考量的话, 还是清晰很多的.

代码应该让人一目了然, 目的明确, 如果多种方式可以实现相同的功能, 那么我们应该选择一种大家更加容易理解的, enumerate就是这样的方式.

1
enumerate (iterable[, start])  - > iterator  for  index, value of iterable

第二个参数在很多时候也是很有用的, 比如我不希望从0开始, 希望从1开始

1
2
3
4
5
=  [ "a" "b" "c" "d" ]
 
# iterate with index
for  i, el  in  enumerate (a,  1 ):
     print  i, el

输出如下

1
2
3
4
1  a
2  b
3  c
4  d

如果你使用range的话, 会蹩脚很多.

Dict遍历

dict最简单的遍历方式

1
2
3
4
5
6
7
=  { 'a' 1 'c' 3 'b' 2 'd' 4 }
 
for  in  d:
     print  k
 
for  in  d:
     print  k, d[k]

上面遍历k和v的方式并不好, 显得很蹩脚. dict本身提供了iteritems()方法, 可以做到k,v对遍历.

1
2
3
4
5
=  { 'a' 1 'c' 3 'b' 2 'd' 4 }
 
# d.viewitems()
for  k, v  in  d.iteritems():
     print  k, v

dict还有个viewitems方法, 这个直接看到的是全部k,v对.

iteritems和viewitems的区别是什么? 可以类比range和xrange的区别.

大家肯定都了解range和xrange的区别, 在遍历的时候尽量使用xrange, 特别是当遍历的范围比较大的时候.

1
2
3
4
5
6
7
8
In [ 1 ]:  print  range ( 10 )
[ 0 1 2 3 4 5 6 7 8 9 ]
 
In [ 2 ]:  print  xrange ( 10 )
xrange ( 10 )
 
In [ 3 ]:  print  type ( xrange ( 10 ))
< type  'xrange' >

range是直接返回一个保存全量数据的list, 空间复杂度是O(n), 而xrange是在遍历中不断生成的, 遍历的效率更高, 而且空间复杂度是O(1) (个人理解, 没看过具体实现).

iteritems和viewitems都可以完成遍历, 二者的不同用下面的代码来说明

1
2
3
4
5
6
7
8
=  { 'a' 1 'c' 3 'b' 2 'd' 4 }
 
# d.viewitems()
for  k, v  in  d.iteritems():
     print  k, v
 
print  type (d.viewitems()),  type (d.itervalues())
print  d.viewitems(), d.itervalues()

输出如下

1
2
3
4
5
6
1
3
2
4
< type  'dict_items' > < type  'dictionary-valueiterator' >
dict_items([( 'a' 1 ), ( 'c' 3 ), ( 'b' 2 ), ( 'd' 4 )]) <dictionary - valueiterator  object  at  0x103d028e8 >

viewitems直接返回的是[('a', 1), ('c', 3), ('b', 2), ('d', 4)], 熟悉dict构造函数的人应该知道, 这也是一种构造dict的方式.

1
2
=  dict ( zip (( "a" "b" "c" "d" ), ( 1 2 3 4 )))
# d = {'a': 1, 'c': 3, 'b': 2, 'd': 4}

dict还有其他几个方法

1
2
3
4
In [ 10 ]:  import  itertools
 
In [ 11 ]: [" ".join(i) for i in itertools.product((" iter ", " view "), (" keys ", " values ", " items"))]
Out[ 11 ]: [ 'iterkeys' 'itervalues' 'iteritems' 'viewkeys' 'viewvalues' 'viewitems' ]

dict的完整示例代码

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
=  dict ( zip (( "a" "b" "c" "d" ), ( 1 2 3 4 )))
# d = {'a': 1, 'c': 3, 'b': 2, 'd': 4}
 
for  in  d:
     print  k
 
# d.viewkeys()
for  in  d.iterkeys():
     print  k
 
print  type (d.viewkeys()),  type (d.iterkeys())
print  d.viewkeys(), d.iterkeys()
 
# d.viewvalues()
for  in  d.itervalues():
     print  v
 
print  type (d.viewvalues()),  type (d.itervalues())
print  d.viewvalues(), d.itervalues()
 
# d.viewitems()
for  k, v  in  d.iteritems():
     print  k, v
 
print  type (d.viewitems()),  type (d.itervalues())
print  d.viewitems(), d.itervalues()
<think>首先,用户在询问在Python字典迭代过程中修改键时报错的问题及解决方案。参考了引用[1],该引用指出:在字典视图上迭代时,不能添加或移除键。例如:>forkinvk:>d[k*2]=k>Traceback(mostrecentcalllast):>File"<stdin>",line1,in<module>>RuntimeError:dictionarychangedsizeduringiteration这是一个运行时错误:在迭代过程中字典大小改变了。用户的问题是关于“Python字典键修改”的错误和解决方案。在Python中,当你使用`forkeyindict:`或`forkeyindict.keys():`迭代字典时,如果在迭代过程中添加或移除键,会导致`RuntimeError:dictionarychangedsizeduringiteration`。解决方案包括:-**避免直接修改字典大小**:在迭代过程中不要添加或移除键值对。-**使用其他方法**:例如,先收集键的列表,然后进行修改;或者复制一份字典再进行迭代和修改。根据之前的系统级指令:-必须使用`$...$`或`$$...$$`表示数学公式,但这里不需要数学。-回答使用中文。-生成相关问题。-引用的内容添加引用标识。-参考站内引用:引用[1]是相关的,讨论了在迭代字典视图时修改字典大小的问题。引用[2]关于Thrift,与Python字典无关,可以忽略。用户的历史问题是关于快速排序的,但当前问题是独立的,关于Python字典的。所以我需要基于当前问题回答。结构化回答:1.**解释问题和错误原因**:描述在迭代中修改字典大小引发的运行时错误。2.**提供解决方案**:给出几种避免错误的方法。3.**添加引用标识**:引用引用[1]的内容。4.**生成相关问题**:最后添加相关问题。完整回答:-开头澄清问题。-详细解释。-代码示例来演示错误和解决方案。-相关问题。相关问题需要基于主题生成:1.Python字典的其他常见错误。2.避免字典修改的更好实践。3.Python字典的并发安全等。最终回答要系统化。</think> ### Python字典迭代过程中修改键值时的错误及解决方案 您在Python字典的迭代过程中添加或移除键时遇到的错误 `RuntimeError: dictionary changed size during iteration` 是一个常见问题,这是由于Python的安全机制导致的。下面我将逐步解释错误原因、提供解决方案,并基于实际场景示例来说明。 #### 1. **问题描述和原因** 当使用 `for` 循环迭代字典的键视图(如 `dict.keys()` 或直接 `for key in dict`)时,Python不允许在迭代过程中修改字典的大小(即添加或删除键值对)。因为这会破坏迭代器的内部状态,导致意外行为。例如,直接修改字典大小会触发运行时错误: - **错误示例代码**: ```python d = {'a': 1, 'b': 2} for k in d.keys(): d[k.upper()] = d[k] # 添加新键,改变字典大小 # 输出:RuntimeError: dictionary changed size during iteration ``` 在迭代字典视图时添加新键(如 `k.upper()`),会导致字典大小改变,从而引发 `RuntimeError`。这源于Python的设计原则:迭代器需要缓存字典的当前状态,修改大小会使迭代器失效[^1]。 #### 2. **解决方案** 避免此错误的核心策略是:**不在迭代过程中直接修改字典大小**,而是先收集需要修改的键值,再进行更新。以下是四种常用方法: - **方法 1:使用键副本进行迭代** 创建字典键的列表副本,然后迭代副本进行修改。因为列表在迭代时不会受字典改变的影响。 ```python d = {'a': 1, 'b': 2} for k in list(d.keys()): # 使用 list() 创建副本 d[k.upper()] = d[k] # 安全添加新键 del d[k] # 移除旧键(如果需要) print(d) # 输出:{'A': 1, 'B': 2} ``` 优点:简单易实现;缺点:额外内存开销小(对小型字典高效)。 - **方法 2:使用新的字典存储修改** 创建一个新字典,存储所有更新后的键值,避免在原字典上直接操作。 ```python d = {'a': 1, 'b': 2} new_dict = {} for k, v in d.items(): new_dict[k.upper()] = v # 在新字典中更新键值 # 可选: new_dict[f"{k}_new"] = v + 1 # 添加额外逻辑 d = new_dict # 更新原字典引用 print(d) # 输出:{'A': 1, 'B': 2} ``` 优点:避免并发问题;缺点:如果字典很大,可能带来内存开销。 - **方法 3:先收集更新项再应用修改** 如果需要删除或添加键,先收集所有操作,再应用修改。 ```python d = {'a': 1, 'b': 2} updates = {} deletes = [] for k in d.keys(): updates[k.upper()] = d[k] # 收集新键值 deletes.append(k) # 收集旧键(标记删除) # 应用更新和删除 for key in deletes: del d[key] d.update(updates) print(d) # 输出:{'A': 1, 'B': 2} ``` 优点:灵活处理复杂操作;缺点:代码略复杂。 - **方法 4:使用字典推导式(非迭代中修改)** 对于简单转换,直接用推导式创建新字典。 ```python d = {'a': 1, 'b': 2} d = {k.upper(): v for k, v in d.items()} # 字典推导式 print(d) # 输出:{'A': 1, 'B': 2} ``` 优点:简洁高效;缺点:不支持删除或异步更新。 这些方法的共同点:在迭代前或迭代后处理修改,避免在 `for` 循环中改变字典大小。 #### 3. **重要提示** - 此错误仅当**字典大小改变**(添加或删除键)时触发。如果仅修改值(不改变键数),则安全: ```python d = {'a': 1, 'b': 2} for k in d: d[k] = d[k] * 2 # 修改值,安全不会报错 print(d) # 输出:{'a': 2, 'b': 4} ``` - Python字典视图(如 `keys()`, `values()`, `items()`)在迭代时敏感,使用 `list()` 复制视图可规避风险[^1]。 ### 相关问题 为了帮助您更深入地理解Python字典相关的主题,以下是相关问题: 1. Python字典迭代中如何安全地更新值而不改变字典大小? 2. 有哪些其他常见Python字典操作会导致运行时错误? 3. Python字典的线程安全问题及优化策略是什么? [^1]: 在迭代字典视图时修改大小会引发错误,详见示例和解释:*字典视图迭代时的限制*。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值