Python RuntimeError:在迭代过程中,字典更改了大小-在使用defaultdict上的iteritems进行迭代期间

Python RuntimeError:在迭代过程中,字典更改了大小-在使用defaultdict上的iteritems进行迭代期间,python,dictionary,iterator,runtime-error,Python,Dictionary,Iterator,Runtime Error,在回答一个特殊的问题时,我偶然发现了一个我无法解释的特殊问题。不幸的是,前两个谷歌搜索页面返回了一个同样没有帮助的页面 问题代码 >>> somedata=[random.randint(1,1000) for i in xrange(1,10000)] >>> somehash=collections.defaultdict(int) >>> for d in somedata: somehash[d]+=1 >&

在回答一个特殊的问题时,我偶然发现了一个我无法解释的特殊问题。不幸的是,前两个谷歌搜索页面返回了一个同样没有帮助的页面

问题代码

>>> 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
>>>

在迭代字典时添加或删除字典项是错误的。由于
somehash
是一个
defaultdict
,即使是行中看起来像只读访问的

if somehash[maxkey] > k:

可能会添加一个新密钥--导致您遇到的错误。

正如Sven所解释的,您遇到的错误是由于
defaultdict
的工作方式造成的。在
defaultdict
中执行查找时,如果键不存在,将检索默认值(因此命名),并将键添加到字典中(使用默认值)。这是
运行时错误的根源

可以执行以下操作以避免此问题:

for k, v in somehash.items():
    if somehash[maxkey] > v:
        maxkey = k
主要区别在于
somehash.items()
返回一个(键、值)元组列表,因此实际上是在该列表上迭代,而不是
somehash
本身。对于
.keys()
.iterkeys()

您正在生成9999个(多少)介于1和1000之间的随机整数,存储在
somedata
中,它用作
somehash
的键,用于存储somedata中出现的数字

由于
maxkey=0
,该键将永远不存在。当您使用defaultdict时,在迭代过程中正确地抛出一个错误,正如*FastTurl*已经指出的那样

使用
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  

我看到您正在使用Python2.7,它有一个名为
Counter
的新集合类,用于计算哈希对象。使用
计数器
应比上述代码快,并将代码减少到:

somedata=[random.randint(1,1000) for i in xrange(1,10000)]
somehash=collections.Counter(somedata)

具体地说,在第一次迭代中出现错误,其中
maxkey=0
。您的其他键来自dict,因此它们已经存在。这是一个问题,使用普通dict会引发一个键错误,但这仍然没有被注意到。比较
somehash[maxkey]>k
将dict中的计数与哈希值进行比较,这似乎毫无意义。你想干什么?@Sven,这是个打字错误。我会改正的。它应该是
somehash[maxkey]>v
,我试图迭代并确定字典中的最大值,同时只跟踪键。对我来说不起作用,必须显式地具体化项(通过
列表(dict.items())
)来停止错误
.items()
返回字典的视图,该视图反映基础字典中的更改,因此可能会导致相同的问题
somedata=[random.randint(1,1000) for i in xrange(1,10000)]
somehash=collections.Counter(somedata)