我有一个带时间戳的字典,我想迭代它并删除被认为过时的项目(在Python中) 我最好怎么做? 这段代码给了我 RuntimeError:字典在迭代期间改变了大小:
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
答案 0 :(得分:4)
迭代时不能修改集合。
有几种解决方法:
请注意,尽管在项目上进行了迭代,但您已经明确地获取了值,因此没有理由在这里使用#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
类中。
答案 1 :(得分:1)
看看这个例子。也许它会有所帮助。请记住,当您从列表或字典中删除元素时,从末尾开始。避免使用 iteritems()方法。
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