Exploit Python Iterator: An Example

Programmers are warned by the following statement: never modify a container itself while using an iterator that goes through it. It makes sense because it is usually hard to track what is going on. Even worse, different programming languages have different implementation on iterators, so the same logic may not work everywhere.

In this article I will demonstrate how Python iterator works by exploiting it, namely modify the container while accessing elements.

Here is a piece of test code.

1
2
3
4
5
6
7
8
9
10
l = [i for i in range(1, 11)]

def iterate(data):
for a in data:
b = data.pop(0)
print(a, b)

if __name__ == "__main__":
print(l)
iterate(l)

When executing, the following results are returned on terminal.

1
2
3
4
5
6
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
1 1
3 2
5 3
7 4
9 5

In the loop, each time we remove the first element of the list. In the first time, 1 is the first element, thus it is caught by the iterator. In the second time of loop, 3 is the second element of the list since 1 has been removed, so 3 is caught by the iterator. The loop continues until the iterator reaches the end of list. We can conclude that:

The Python iterator always yields element on increasing offset corresponding to the current container, regardless of the adjacent relationship between any two elements.