Iterating while mutating
Changing a list or dictionary while iterating over it can produce skipped items, repeated work, or runtime errors. It is one of those bugs that often looks fine in a small example and fails later in real data.
What is happening?
Here is a common list bug:
items = [1, 2, 3, 4]
for item in items:
if item % 2 == 0:
items.remove(item)
print(items)
Output:
[1, 3]
That result happens to look correct here, but the pattern is still unsafe because the list is being modified while the loop is walking through it.
A similar pattern with dictionaries can raise an error immediately.
Why this matters
Mutation changes the structure the iterator is relying on. That can lead to:
- skipped elements
- confusing ordering behavior
- dictionary size errors
- hard-to-reproduce data bugs
Prefer one of these patterns
Build a new collection:
items = [1, 2, 3, 4]
filtered = [item for item in items if item % 2 != 0]
Or iterate over a copy when mutation is truly intended:
items = [1, 2, 3, 4]
for item in items[:]:
if item % 2 == 0:
items.remove(item)
Both options make the behavior much easier to reason about.
Rules of thumb
- Avoid mutating a collection while iterating over it.
- Prefer building a new list or dictionary.
- Iterate over a copy only when in-place mutation is intentional.
- If loop behavior feels inconsistent, check for hidden mutation first.