Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
464 views
in Technique[技术] by (71.8m points)

python - 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()

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.

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)

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.

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

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.

By contrast, the behaviour for dicts and sets is totally implementation specific since the iteration order may change depending on the hashing.

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.

Note that collections.deque also raises a RuntimeError in this case, despite being ordered.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...