运行时错误:在默认字典的迭代中,字典大小发生变化
在这里回答一个特定问题时,我遇到了一个奇怪的问题,自己却说不清楚。可惜的是,谷歌搜索的前两页结果中,有一个SO页面也没有帮助。
问题代码
>>> somedata=[random.randint(1,1000) for i in xrange(1,10000)]
>>> somehash=collections.defaultdict(int)
>>> for d in somedata:
somehash[d]+=1
>>> maxkey=0
>>> for k,v in somehash.iteritems():
if somehash[maxkey] > v:
maxkey=k
Traceback (most recent call last):
File "<pyshell#700>", line 1, in <module>
for k,v in somehash.iteritems():
RuntimeError: dictionary changed size during iteration
>>> for k,v in somehash.iteritems():
if somehash[maxkey] > v:
maxkey=k
>>>
由于某种奇怪的原因,第一次我遍历字典时,Python出现了问题,但后面的执行就没问题了。就像例子中显示的,第一次遍历字典时,它给了我一个运行时错误,但下次就没有再抱怨了。
你知道可能出了什么问题吗?
如果需要的话,这里还有一些信息
>>> sys.version_info
sys.version_info(major=2, minor=7, micro=0, releaselevel='final', serial=0)
>>> sys.version
'2.7 (r27:82525, Jul 4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)]'
OS: Microsoft Windows [Version 6.1.7601] (Windows 7)
3 个回答
你正在生成9999个(有点)随机的整数,这些整数的范围在1到1000之间,存储在somedata
里。然后你用这些整数作为somehash
的键,来记录这些数字在
因为maxkey=0
,所以这个键永远不会存在。你使用的是一个叫做defaultdict的东西,当每个键第一次出现时,会自动创建一个条目,使用default_factory
函数返回一个空列表,因此在迭代时会正确地抛出错误,正如*FastTurtle*已经指出的那样。
你可以使用get
方法来安全地获取一个项目。
import random
import collections
somedata=[random.randint(1,1000) for i in xrange(1,10000)]
somehash=collections.defaultdict(int)
for d in somedata:
somehash[d]+=1
maxkey=0
for k,v in somehash.iteritems():
if somehash.get(maxkey) > v:
maxkey=k
print k,v
我看到你在使用Python 2.7,它有一个新的集合类叫Counter
,用于计数可哈希的对象。使用Counter
应该比上面的代码更快,而且可以把你的代码简化为:
somedata=[random.randint(1,1000) for i in xrange(1,10000)]
somehash=collections.Counter(somedata)
正如Sven所解释的,你遇到的错误是因为defaultdict
的工作方式。当你在defaultdict
中查找一个键时,如果这个键不存在,它会自动获取一个默认值(这就是它名字的由来),并把这个键和默认值一起添加到字典里。这就是你出现RuntimeError
的原因。
为了避免这个问题,你可以这样做:
for k, v in somehash.items():
if somehash[maxkey] > v:
maxkey = k
主要的区别在于,somehash.items()
返回的是一个包含(键,值)对的列表,所以你实际上是在遍历这个列表,而不是在遍历somehash
本身。.keys()
和.iterkeys()
也是一样的道理。
在遍历字典的时候,如果你同时添加或删除字典里的项目,那就是个错误。因为somehash
是一个defaultdict
,所以在下面这行代码中,虽然看起来只是读取数据
if somehash[maxkey] > k:
但实际上可能会添加一个新的键,这就会导致你遇到的错误。