在迭代过程中修改列表和字典,为什么字典失败? [英] Modify list and dictionary during iteration, why does it fail on dict?

查看:91
本文介绍了在迭代过程中修改列表和字典,为什么字典失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们考虑以下代码,该代码在每次迭代中删除一个项目时会在列表上进行迭代:

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. lists are ordered, dicts (prior to Python 3.6/3.7) and sets are not. So modifying a lists 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 dicts and sets is totally implementation specific since the iteration order may change depending on the hashing.

您会得到一个带有collections.OrderedDictRunTimeError,大概是为了与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 dicts 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆