迭代集合时不能修改集合。
有几种方法可以解决这个问题:
- (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
类或其他东西。