Why is it not safe to change the sequence that repeats?

It is incorrect to change a sequence repeated in a loop (this can only happen for mutable types of sequences, such as lists). If you need to change the list that you are repeating (for example, to duplicate selected items), you must iterate over the copy. Slice notation makes this especially convenient:

>>> for x in a[:]: # make a slice copy of the entire list ... if len(x) > 6: a.insert(0, x) ... >>> a ['defenestrate', 'cat', 'window', 'defenestrate'] 

why is it not safe to just do for x in a ??

+16
python
Jul 27. '10 at 18:29
source share
3 answers

Without too technical:

If you iterate through a mutable sequence in Python and the sequence changes when it repeats, it is not always clear what will happen. If you insert an element into a sequence during iteration through it, what is now wise to be considered the β€œnext” element in the sequence? What if you delete the next object?

For this reason, iterating with the variable sequence during its change leads to unspecified behavior. Anything can happen, depending on how the list is implemented. :-)

+13
Jul 27 '10 at 18:38
source share

This is a common problem in many languages. If you have a linear data structure and you repeat it, something should keep track of where you are in the structure. It may be the current pointer or a pointer, but it is some kind of finger pointing to the "current location".

If you modify the list during iteration, this cursor is likely to be wrong.

A common problem is that you delete the item under the cursor, all slide down, the next iteration of the loop increases the cursor, and you accidentally missed the item.

Some data structure implementations offer the ability to delete items during an iteration, but most of them do not work.

+12
Jul 27 '10 at 18:35
source share

When you modify the collection in which you iterate, the iterator may behave unpredictably, for example, skip items or return the same item twice.

This code loop endlessly when I run it:

 >>> a = [ 'foo', 'bar', 'baz' ] >>> for x in a: ... if x == 'bar': a.insert(0, 'oops') 

This is because the iterator uses the index to track where it is in the list. Adding an element to the beginning of the list causes the bar element to return again, rather than moving the iterator to the next element.

+1
Jul 27 '10 at 18:34
source share



All Articles