Modifying a sequence while iterating over it can cause undesired behavior due to the way the iterator is build. To avoid this problem, a simple solution is to iterate over a copy of the list. For example, you’ll obtain a copy of list_1
by using the slice notation with default values list_1[:]
. Because you iterate over a copy of the list, you can modify the original list without damaging the iterator.
In the following quick article, I’ll explain this problem and its solution in greater detail. Let’s go!
Problem: Given a sequence such as a Python list in Python. How to modify the sequence while iterating over it?
Example: Say, you have a Python list of strings:
# Given list of strings words = ['cat', 'mouse', 'dog']
You want to iterate over each element and check if it is longer than 3 characters. If it is, you want to insert it at the beginning so that all strings with more than 3 chars are placed at the beginning. You desire the following list with the 4-character word ‘mouse’ placed at the beginning of the list:
# Your desired result: words = ['mouse', 'cat', 'dog']
Why is this a challenging problem?
This problem is not as simple as removing elements from a sequence over which you iterate. Doing this can lead to unspecified behavior as explained in the following.
Before entering the for loop, the Python interpreter creates an iterator object. The iterator object provides a method next()
returning the next element in the sequence.
To achieve this, the iterator extracts, on creation time, information like the size of the sequence. If you modify the sequence “on the go”, this information becomes invalid.
For example, if the number of elements changes at runtime, the iterator object may believe it is ready, while there are still objects in it.
Solution: The following code provides a simple solution—to iterate over a copy of the list using the slicing notation. In other words, the code copies the list first and iterates over the copy. With this method, we can safely modify the original list as this will not affect the copy in any way. The slice notation is a very convenient way to copy sequences.
words = ['cat', 'mouse', 'dog'] for w in words[:]: if len(w) > 3: words.insert(0, w) print(words)
If you use this code snippet, the first element of the list will be 'mouse'
—and the output is:
# Your desired result: words = ['mouse', 'cat', 'dog']
You can solve a related puzzle on our Finxter.com app to improve your understanding of basic Python operators—and have some fun in the process! π
Exercise: Take a guess—what’s the output of this code puzzle?
Are you a master coder?
Test your skills now!
You can watch a related video here: