关于字典:dict在迭代期间改变了大小,但没有在Python中编辑它

dict changed size during iteration, but not editing it in Python

我在python中得到了dict changed size during iteration错误,尽管我没有修改嵌套的dict,但我正在从原始文件中删除,而不是从循环的副本中删除。

1
2
3
4
5
6
test = arr.copy()
for map in test:
    for mID in test[map]:  #here is dictionary changed size during iteration
        v = test[map][mID]['val']
        if v < 1:
            del arr[map][mID]

我忽略了什么吗?


你在抄字典,但用的是浅薄的副本。

由于您正在迭代子dict(它没有被复制,arrtest之间的引用是相同的),所以会得到这个错误。

使用copy模块的deepcopy功能,如下所示:

1
2
import copy
test = copy.deepcopy(arr)

但是,对于这样的问题,深度复制对象是多余的。您可以这样迭代一个项目的副本(也可以:总是迭代key+值,这样就不必在循环中按key访问值):

1
2
3
4
5
for map,map_values in arr.items():
    for mID,subdict in list(map_values.items()):  # make a copy/force iteration using `list`
        v = subdict['val']
        if v < 1:
            del map_values[mID]


其他的答案是正确的:copy()返回一本浅薄的字典,所以arr[map]将是test[map]的副本,但arr[map][mID]arr[map][mID]将完全是test[map][mID]的副本。

下面的模式显示了这种情况:

1
2
3
4
5
6
7
arr  -+-> 'map1' -+-> { 'id1':{'val':0}, ... }
      |           |
      +-> 'map2' ---+-> { 'id1':{'val':2}, ... }
                  | |
test -+-> 'map1' -+ |
      |             |
      +-> 'map2' ---+

当您试图删除arr['map1']['id1']时,您也试图删除test['map1']['id1'],但是您正在迭代test['map1']。这就是为什么您会得到这个错误(当您迭代它时,test['map1']的大小可能不会改变)。

但我认为江户一号〔2〕不是好的解决办法。您所需要的只是复制arr[map]的键,并在此副本上迭代。

1
2
3
4
5
for map in arr:
    for mID in list(arr[map]): # here's the copy of the keys
        v = arr[map][mID]['val']
        if v < 1:
            del arr[map][mID] # allowed because you are not iterating on the dict, but on the copy of the keys

网上试试!

一些阅读:如何避免"runtimeerror:dictionary changed size during iteration"错误?


如果使用嵌套的dict,则应创建一个深度副本。

1
2
import copy
test = copy.deepcopy(arr)

请注意,copy.copydict.copy只创建浅色副本!

dict.copy()的文档:

Return a shallow copy of the dictionary.