Python中遍历字典过程中更改元素导致异常的解决方法

   2016-05-23 0
核心提示:这篇文章主要介绍了Python中遍历字典过程中更改元素导致错误的解决方法,针对增删元素后出现dictionary changed size during iteration的异常解决做出讨论和解决,需要的朋友可以参考下

先来回顾一下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

 

执行结果:

##########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字典遍历的“争论”....
先摘抄下:

#这里初始化一个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]

这个写法让我眼前一亮:怎么还有这个语法?
再仔细一看,他可能是这个意思:

#!/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到有个解决方案

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的资料里面还有一个版本

#V1 if X else V2
s = None
a = "not null" if s == None else s
print a
#'not null'

后来发帖在华蟒用户组(中文Python技术邮件列表)中提到后众多大神解答如下:

>>> 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
还可以用这个写法:

>>> d = {k:v for k,v in d.iteritems() if v !=0 }

 
标签: Python 字典 遍历
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 如何在Abaqus的python中调用Matlab程序
    目录1. 确定版本信息2. 备份python3. 设置环境变量4. 安装程序5. 调试运行参考资料Abaqus2018操作系统Win10 64位Python版本2.7(路径C:\SIMULIA\CAE\2018\win_b64\tools\SMApy\python2.7)2. 备份python将上述的“python2.7”文件夹复制出来,避免因操作错误
    03-16
  • SICP:复数的直角和极坐标的表示(Python实现)
    SICP:复数的直角和极坐标的表示(Python实现)
    数据抽象屏障是控制复杂性的强有力工具,然而这种类型的数据抽象还不够强大有力。从一个另一个角度看,对于一个数据对象可能存在多种有用的表示方式,且我们希望所设计的系统能够处理多种表示形式。比如,复数就可以表示为两种几乎等价的形式:直角坐标形式(
    03-16
  • [个人发展] 我做了一个可以永远谈论任何事情的女士对话AI(TypeScript,Python)
    [个人发展] 我做了一个可以永远谈论任何事情的
    在个人发展中对话式人工智能服务 Eveki我做了虚构角色1这是一项以人工智能为特色的服务,可以再现并享受自然对话。这一次,作为第一个艾小姐发表了。请先尝试实物。服务概览与人工智能对话基本上只需输入您的信息是。对话是用女士的语言进行的,就像人类一样
    03-08
  • ruby写爬虫 ruby python
    ruby写爬虫 ruby python
    http://www.javaeye.com/topic/545160爬虫性能比较http://www.rubyrailways.com/data-extraction-for-web-20-screen-scraping-in-rubyrails/srcapihttp://huacnlee.com/blog/ruby-scrapi-collect-koubei  2009年4月22日 星期三用ruby写的一个网络爬虫程序前
    03-08
  • sf02_选择排序算法Java Python rust 实现
    Java 实现package common;public class SimpleArithmetic {/** * 选择排序 * 输入整形数组:a[n] 【4、5、3、7】 * 1. 取数组编号为i(i属于[0 , n-2])的数组值 a[i],即第一重循环 * 2. 假定a[i]为数组a[k](k属于[i,n-1])中的最小值a[min],即执行初始化 min =i
    02-09
  • Python vs Ruby: 谁是最好的 web 开发语言?
    Python 和 Ruby 都是目前用来开发 websites、web-based apps 和 web services 的流行编程语言之一。 这两种语言在许多方面有相似之处。它们都是高级的面向对象的编程语言,都是交互式脚本语言、都提供标准库且支持持久化。但是,Python 和 Ruby 的解决方法却
    02-09
  • 详解Python手写数字识别模型的构建与使用
    详解Python手写数字识别模型的构建与使用
    目录一:手写数字模型构建与保存1 加载数据集2 特征数据 标签数据3 训练集 测试集4 数据流图 输入层5 隐藏层6 损失函数7 梯度下降算法8 输出损失值 9 模型 保存与使用10 完整源码分享二:手写数字模型使用与测试一:手写数字模型构建与保存1 加载数据集# 1加
  • Python asyncore socket客户端实现方法详解
    Python asyncore socket客户端实现方法详解
    目录介绍1.定义类并且继承 asyncore.dispatcher2.实现类中的回调代码调用父类方法创建socket对象连接服务器3.创建对象并且执行asyncore.loop进入运行循环服务端示例代码运行结果注意介绍asyncore库是python的一个标准库,提供了以异步的方式写入套接字服务的
  • Python+Sklearn实现异常检测
    目录离群检测 与 新奇检测Sklearn 中支持的方法孤立森林 IsolationForestLocal Outlier FactorOneClassSVMElliptic Envelope离群检测 与 新奇检测很多应用场景都需要能够确定样本是否属于与现有的分布,或者应该被视为不同的分布。离群检测(Outlier detectio
  • Python基础教程之while循环用法讲解 Python中的while循环
    Python基础教程之while循环用法讲解 Python中的
    目录1.while 循环2.无限循环3、while 循环使用 else 语句4、简单语句组附小练习:总结1.while 循环Python 中 while 语句的一般形式:while 判断条件(condition):    执行语句(statements)……执行流程图如下:同样需要注意冒号和缩进。另外,在 Python 中
点击排行