在迭代过程中修改列表和字典,为什么字典失败? [英] Modify list and dictionary during iteration, why does it fail on dict?
问题描述
让我们考虑以下代码,该代码在每次迭代中删除一个项目时会在列表上进行迭代:
Let's consider this code which iterates over a list while removing an item each iteration:
x = list(range(5))
for i in x:
print(i)
x.pop()
它将打印0, 1, 2
.由于前两次迭代删除了列表中的后两个元素,因此只打印了前三个元素.
It will print 0, 1, 2
. Only the first three elements are printed since the last two elements in the list were removed by the first two iterations.
但是,如果您在 dict 上尝试类似的操作:
But if you try something similar on a dict:
y = {i: i for i in range(5)}
for i in y:
print(i)
y.pop(i)
它将先打印0
,然后再举起RuntimeError: dictionary changed size during iteration
,因为我们正在迭代时从字典中删除键.
It will print 0
, then raise RuntimeError: dictionary changed size during iteration
, because we are removing a key from the dictionary while iterating over it.
当然,在迭代过程中修改列表是不好的.但是,为什么不像字典那样引发RuntimeError
呢?这种行为有什么充分的理由吗?
Of course, modifying a list during iteration is bad. But why is a RuntimeError
not raised as in the case of dictionary? Is there any good reason for this behaviour?
推荐答案
我认为原因很简单. list
是有序的,dict
(在Python 3.6/3.7之前)和set
是无序的.因此,最好不建议在迭代时修改list
s,但这会导致一致,可重现和有保证的行为
I think the reason is simple. list
s are ordered, dict
s (prior to Python 3.6/3.7) and set
s are not. So modifying a list
s as you iterate may be not advised as best practise, but it leads to consistent, reproducible, and guaranteed behaviour.
您可以使用此方法,例如,假设您想将偶数个元素的list
拆分为一半,然后将第二个元素取反:
You could use this, for example let's say you wanted to split a list
with an even number of elements in half and reverse the 2nd half:
>>> lst = [0,1,2,3]
>>> lst2 = [lst.pop() for _ in lst]
>>> lst, lst2
([0, 1], [3, 2])
当然,执行此操作有更好,更直观的方法,但要点是可行.
Of course, there are much better and more intuitive ways to perform this operation, but the point is it works.
相反,dict
s和set
s的行为完全是实现特定的,因为迭代顺序可能会根据散列而改变.
By contrast, the behaviour for dict
s and set
s is totally implementation specific since the iteration order may change depending on the hashing.
您会得到一个带有collections.OrderedDict
的RunTimeError
,大概是为了与dict
行为保持一致.我认为dict
行为不会在Python 3.6之后发生任何变化(保证dict
保持插入顺序),因为在没有实际用例的情况下它将破坏向后兼容性.
You get a RunTimeError
with collections.OrderedDict
, presumably for consistency with the dict
behaviour. I don't think any change in the dict
behaviour is likely after Python 3.6 (where dict
s are guaranteed to maintain insertion ordered) since it would break backward compatibility for no real use cases.
请注意,尽管已订购collections.deque
,但在这种情况下也会引发RuntimeError
.
Note that collections.deque
also raises a RuntimeError
in this case, despite being ordered.
这篇关于在迭代过程中修改列表和字典,为什么字典失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!