I'm iterating a list as follows:
some_list = [1, 2, 3, 4]
another_list = [1, 2, 3, 4]
for idx, item in enumerate(some_list):
del some_list[idx]
for item in another_list:
another_list.remove(item)
When I print out the contents of the lists
>>> some_list
[2, 4]
>>> another_list
[2, 4]
I'm aware that Python doesn't support modifying a list
while iterating over it and the right way is to iterate over copy of list instead (so please don't downvote). But I want to know what exactly happens behind the scenes i.e. Why is the output of the above snippet [2, 4]
?
As we know, every item in a list lives at its own unique index; which are in order, starting from 0. If we remove an item, any item with an index greater than the one we've removed has now been shifted down.
And here's why that matters:
In this loop, we're removing all the elements, so we should end up with
foo == []
, right? This is not the case. In our first trip through the loop, we remove the item at index0
, and the item at index1
becomes the item at index0
. Our next time through the loop, we remove the item at index1
which was previously the item at index 2.In just the first two iterations, we've removed
'a'
and'c'
from the array, *but we've neglected to remove'b'
. Once we get to the third iteration (where we though we'd remove index2
), there is no longer an element at index2
; only indices0
and1
. An exception is raised when we try to remove the non-existent item at index2
, and the loop is stopped. The result is a mangled array that looks like this:['a', 'd']
.You can use a self-made iterator that shows (in this case
print
s) the state of the iterator:Then use it around the list you want to check:
This should illustrate what happens in that case:
It only works for sequences though. It's more complicated for mappings or sets.