Python字典循环RuntimeError报错分析
情况如上所示,当运行程序的时候,报错内容为:RuntimeError: dictionary changed size during iteration
分析
我们知道Python字典是用哈希表(hash table)实现的。哈希表是一个数组,它的索引是对键运用哈希函数(hash function)求得的。for cn_id in cn_map_info:
这种方式是通过iterator遍历字典,但是在遍历中改变了他,比如增删某个元素,就会导致遍历退出,并且抛出dictionary changed size during iteration
的异常。
在我们平常使用中我们知道Python是推荐使用迭代器的,也就是for k in xdict
形式。其次,在遍历中删除容器中的元素,在C++ STL 和 Python等库中,都是不推荐的,因为这种情况往往说明了你的设计方案有问题,所有都有特殊要求,对应到Python中,就是要使用xdict.key()
做一个拷贝。最后,所有的Python容器都不承诺线程安全,你要多线程做这件事,本身就必须得加锁,这也说明了业务代码设计有问题的。
但由"遍历中删除特定元素"这种特例,得出"遍历dict的时候,养成使用for k in d.keys()
的习惯",我觉得有必要纠正一下,在普通的遍历中,我们还是应该使用for k in xdict
高效Pythonic的方法。
另外,对于"遍历中删除元素"这种需求,Pythonic的做法是 xdict = {k, v for adict.iteritems() if v != 0}
或 alist = [i for i in alist if i != 0]
Python字典实现原理:https://harveyqing.gitbooks.io/python-read-and-write/content/python_advance/python_dict_implementation.html
解决方法
解决方法是在遍历字典键值,以字典键值为依据遍历,这样改变了value以后不会影响遍历继续。
Python2解决如下:
for cn_id in cn_map_info.keys():
if cn_id not in monitor_id_list:
del(cn_map_info[cn_id])
for cn_id in cn_map_info.keys()
这种方式是通过一个列表来依次获取每个key
(cn_map_info.keys()返回的列表),所以遍历过程不会奔溃。
Python3解决如下:
for cn_id in list(cn_map_info.keys()):
if cn_id not in monitor_id_list:
del(cn_map_info[cn_id])
同样Python3下也是通过列表来循环所有key,跟原字典不冲突,所以遍历不会奔溃。
为什么Python3下需要需要list()操作,分析如下:
nock:lab nock$ python2.6
Python 2.6.9 (unknown, Jul 14 2015, 19:46:31)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> monitor_id_list = [12, 13, 14, 16, 19, 20]
>>> cn_map_info = {12: 'taiwan', 13: 'hongkong', 15: 'guizhou'}
>>> print(cn_map_info.keys())
[12, 13, 15]
>>> exit()nock:lab nock$ python3
Python 3.5.1 (default, Dec 26 2015, 18:08:53)
[GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> monitor_id_list = [12, 13, 14, 16, 19, 20]
>>> cn_map_info = {12: 'taiwan', 13: 'hongkong', 15: 'guizhou'}
>>> print(cn_map_info.keys())
dict_keys([12, 13, 15])
>>> print(list(cn_map_info.keys()))
[12, 13, 15]
问题很简单明了Python2下xdict.keys()
直接返回的就是列表,而Python3下xdict.keys()
返回的是字典keys对象。
- 数据库连接池、dbutil_知识点全掌握
- Golang 序列化之 ProtoBuf
- Golang RPC 之 gRPC
- 解决连通性问题的四种算法
- 使用shell批量生成数据整合式迁移的脚本(r8笔记第52天)
- Jdbc知识点全整理,你值得拥有 (1)
- SSD: Single Shot MultiBox Detector 深度学习笔记之SSD物体检测模型
- dg broker校验失败的一个奇怪问题(r8笔记第50天)
- golang 几种字符串的连接方式
- 整理ING
- dg broker校验失败的一个奇怪问题(二) (r8笔记第51天)
- Jdbc知识点全整理,你值得拥有 (2)
- 抓住“新代码”的影子 —— 基于GoAhead系列网络摄像头多个漏洞分析
- Python 用OPEN读文件报错 ,路径以及r
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 移动直播集成问题
- TRTC功能咨询
- TKE集群pod镜像拉取失败定位思路
- Android内存管理(JVM 、DVM(dalvik) 、ART简单介绍)
- WordPress 站点地址被恶意篡改的防护方案讨论
- 猿实战06——不一样的地址管理
- Redis常用命令详解
- three.js 制作逻辑转体游戏(下)
- ROS机器人TF基础(坐标相关概念和实践)
- (在模仿中精进数据可视化01) 全国38城居住自由指数可视化
- js字符串/数组常用方法总结
- ThinkPHP5+mpdf 实现富文本生成 PDF文件
- nodejs使用readline逐行读取和写入文件
- go语言逐行读取和写入文件
- SpringBoot中Tomcat是如何启动的