是否可以采用以下形式的算法:
while dict:
k, v = dict.popitem()
... #arbitrary program statements
...
if ...: #reinsert key in some cases
dict[k] = v
无限循环?换句话说,字典/ popitem的实现是否保证如果我弹出一个项目,决定它应该重新插入,并重新执行循环,那么同样的项目将再次弹出?
答案 0 :(得分:2)
当然,这是可能的。但请注意,这取决于精确的实现和 python版本。
dict.popitem()
将在字典哈希表中弹出第一个键值对。由于哈希冲突,重新插入相同的密钥并不能保证它会再次出现在同一个槽中。
使用整数键可以在CPython 2.7中轻松演示:
>>> d = {1: 1, 7: 7}
>>> d.popitem()
(1, 1)
>>> d[1] = 1
>>> d.popitem()
(7, 7)
在CPython中(对于3.3之前的版本),一个小字典从哈希表中的几个插槽开始(随着字典增长,动态创建更多空间),1
和7
发生哈希到同一个插槽。
我第一次从字典中弹出一个项目时,返回了1
,但重新插入1
现在将7
作为第一个键,而是返回它。
(Python 3.3引入了随机哈希种子,使得哈希冲突无法预测)。
但是,当然,如果只是因为它是字典中的最后一个键,完全可能会一次又一次地插入和删除一个键:
>>> d = {1: 1}
>>> d.popitem()
(1, 1)
>>> d[1] = 1
>>> d.popitem()
(1, 1)
你无法轻易预测这将会发生。
请注意,无论接下来弹出什么键,如果您继续将键重新插入字典,您的数据集都不会缩小,最终会以无限循环结束。如果该循环每次处理一个键或重复一系列键都无关紧要。
也许您正在寻找队列?有一个有用且高效的collections.deque()
double-ended queue实现可用:
from collections import deque
to_process = deque(d.items()) # initialize with key-values
while to_process:
k, v = to_process.popleft()
# do work with item
if somecondition:
to_process.append((k, v))
你仍然可以得到一个无限循环(例如,如果你的if
语句总是重新插入相同的键值对),但至少你可以保证你第一次看到在开始循环之前,所有键值对。
答案 1 :(得分:-2)
我认为行为未定义。相反,迭代copy.deepcopy(dict _)。
EG:
for key, value in copy.deepcopy(dict_).items():
do_something_with_dict(dict_)
# do_something_with_dict can change keys or values however it wants, without worrying
# that the for loop will get messed up