0

我有一本带时间戳的字典,我想遍历它并删除被认为过时的项目(在 Python 中)我该怎么做?这段代码给了我RuntimeError: dictionary changed size during iteration

    for key, value in img_dict.iteritems() :
        if (time.time()-float(img_dict[key])) >= stale_img:
            logger.debug('STALE IMAGE FROM '+hexlify(key)+ ' - GOT CLOSED NOW!')
            del img_dict[key]
            data_upload = True
4

2 回答 2

4

迭代集合时不能修改集合。

有几种方法可以解决这个问题:

  • (0) 重新考虑你的设计,看看你是否需要这样做。
  • (1)不要修改收藏;相反,构建一个新的过滤集合。
  • (2) 不要迭代集合;相反,迭代集合的副本
  • (2.5) 对于字典,遍历键的副本,并显式地获取值。

请注意,尽管对项目进行了迭代,但您已经明确地获取了值,因此这里没有理由使用 #2。

以下是其他两个的实现:

new_img_dict = {}
for key in img_dict:
    if (time.time()-float(img_dict[key])) >= stale_img:
        logger.debug('STALE IMAGE FROM '+hexlify(key)+ ' - GOT CLOSED NOW!')
        data_upload = True
   else:
       new_img_dict[key] = img_dict[key]
img_dict = new_img_dict

或者:

for key in img_dict.keys():
    if (time.time()-float(img_dict[key])) >= stale_img:
        logger.debug('STALE IMAGE FROM '+hexlify(key)+ ' - GOT CLOSED NOW!')
        del img_dict[key]
        data_upload = True

(如果您希望它与 Python 3 兼容,img_dict.keys()请不要使用img_dict.keys()[:].)

那么,您如何在两者之间进行选择呢?

第一个通常更容易推理——一般来说,不可变对象和纯操作很容易推理。例如,如果您在某处抛出异常,img_dict将始终拥有原始版本或完成版本,而不是介于两者之间的东西。当然,您不必考虑在迭代时更改某些内容意味着什么。但是,在极少数情况下,很难将“删除 foo 的所有内容”算法转换为“复制不存在 foo 的所有内容”算法。

第一个通常也更容易重写为理解(或对高阶函数的调用,如filter),变成生成器,重构以提取单独的函数等。

对于性能,如果您要过滤掉许多值,第一个通常会更快并且使用更少的内存,而如果您保留大多数值,第二个通常会更好。(不同集合类型的截止值是不同的。通常情况下,它并不重要,如果确实如此,您应该同时编写方式和配置文件。)

回到#0,我认为它可能适用于这种情况。您正在遍历所有键以查看是否有任何键太旧,无法移除它们。例如,如果您使用排序列表或优先级队列,则不必这样做。现在,如果您需要dict更频繁地使用集合而不是刷新旧值,您可能会从更改数据结构中获得更多的成本而不是收益。但为什么不两者兼得?如果您有一个排序的键列表,在将键映射到值的字典之上,那么您可以这样做:

for key in img_sorted_key_list:
    if time.time() - float(key) > stale_img:
        break
    del img_dict[key]

或者,更简单地说:

stale_time = time.time() - stale_img
for key in itertools.takewhile(lambda key: float(key) < stale_time, 
                               img_sorted_key_list):
    del img_dict[key]

您可以将排序的键列表和字典一起包装成一个不错的Cache类或其他东西。

于 2012-12-13T23:25:18.523 回答
1

看看这个例子。也许会有所帮助。请记住,当您删除列表或字典中的元素时,从末尾开始。避免使用ititems()方法。

keysMap = [
      {"key": 1 },
      {"key" : 2 },
      {"key" : 3 },
      {"key" : 4 },
      {"key" : 5 },
      {"key" : 6 }
       ]   
i=len(keysMap)-1
while i > 0 :
    key = keysMap[i]
    if key["key"]==2 :
        del(keysMap[i])
    i=i-1

# Printing the object data after deleting element key=2    
while i < len(keysMap) :
    key = keysMap[i]
    print key
    i=i+1 
于 2012-12-14T01:43:52.083 回答