The trap of modifying a list while iterating over it (and how to fix it).
The library was warm, but Timothy was sweating. He was staring at a list of sensor data on his screen.
"I don't understand," he muttered. "I told it to remove the errors. I wrote the code explicitly. But it keeps missing them."
Margaret glided over, placing a fresh pot of tea on the table. "Missing them?"
"Yes," Timothy said. "I have a list of temperature readings. Any reading below zero is an error—a glitch. I wrote a loop to find them and delete them."
He pointed to his code.
# Timothy's "Cleanup" Loop
temperatures = [10, -5, -2, 15, 20]
for temp in temperatures:
if temp < 0:
print(f"Removing glitch: {temp}")
temperatures.remove(temp)
print(f"Cleaned List: {temperatures}")
"Watch," Timothy said. "I have two negative numbers: -5 and -2. The loop should catch both."
He hit Run.
Removing glitch: -5
Cleaned List: [10, -2, 15, 20]
Timothy threw his hands up. "It missed the -2! It looked right at it and walked on by. Is the loop broken?"
"The loop is not broken," Margaret said calmly. "The floor is moving."
The Disappearing Step
Margaret pulled a few books off the shelf and laid them in a row on the table.
[Book A] [Book B] [Book C] [Book D]
"Imagine these are your list items," she said. "The loop uses an internal pointer—an index—to track where it is. It starts at Index 0."
She pointed to the first book. "Step 0."
Then she moved her finger. "Step 1: The negative number."
"Now," Margaret said, "you tell Python to remove the item at Step 1."
She pulled [Book B] out of the line.
Immediately, she slid the remaining books to the left to fill the gap.
[Book A] [Book C] [Book D]
"What just happened?" she asked.
"Everything shifted left," Timothy said.
"Exactly. The item that was at Index 2 ([Book C]) has now slid into Index 1. But the loop doesn't know the floor moved. The loop just finishes Step 1 and says, 'Okay, time for Step 2'."
She moved her finger to the new Index 2 ([Book D]).
"See?" Margaret whispered. "You skipped [Book C]. Because you destroyed the step you were standing on, the next step fell into the hole, and you stepped right over it."
"That's why it missed the -2!" Timothy realized. "It slid into the slot I just cleared, and the loop jumped past it."
The Snapshot Solution
"So I can never modify a list loop?" Timothy asked.
"You can," Margaret said. "But you must not modify the list you are walking on. You must walk on a map, and modify the territory."
She deleted his loop and typed a subtle change.
# Margaret's Fix: Iterating over a Slice
temperatures = [10, -5, -2, 15, 20]
# The [:] creates a shallow copy (a snapshot) to iterate over
for temp in temperatures[:]:
if temp < 0:
# We modify the ORIGINAL list, not the copy we are walking on
temperatures.remove(temp)
print(f"Cleaned List: {temperatures}")
Output:
Cleaned List: [10, 15, 20]
"By adding [:]," Margaret explained, "you iterate over a shallow copy of the list—the same trick we used to avoid aliasing, but here it serves a different purpose. The loop walks safely on the copy—which never changes—while you delete items from the original temperatures list. The indices on your copy never shift, so you never skip a beat."
The "New World" Approach
"Is there a better way?" Timothy asked. "Removing items one by one feels... slow."
"There is," Margaret smiled. "Instead of fixing a broken world, simply build a new one."
She showed him the List Comprehension approach.
# The Pythonic Way: Create a new list with only the good data
temperatures = [10, -5, -2, 15, 20]
clean_temperatures = [t for t in temperatures if t >= 0]
print(f"Cleaned List: {clean_temperatures}")
"This is often faster and cleaner," she said. "We don't modify. We just filter."
Margaret’s Cheat Sheet
Margaret opened her notebook to the "Loops" section, drawing a warning sign.
- The Trap: Never add or remove items from a list while you are looping over it.
- The Symptom: Skipped items (if removing) or infinite loops (if adding).
- The Reason: When you change the list length, the indices shift, but the loop counter keeps marching forward.
- The Fixes:
-
Iterate over a Copy:
for item in my_list[:]:(Quick fix). -
List Comprehension:
[x for x in my_list if condition](Best for filtering). -
Iterate Backwards:
for item in reversed(my_list):(Advanced—useful when you must modify in-place without copying).
Timothy looked at his clean data. "I feel like I was trying to change a tire while the car was moving."
"Worse," Margaret replied, pouring the tea. "You were trying to remove the floorboards while dancing on them."
In the next episode, Margaret and Timothy will face "The Lazy Baker"—where they discover that some "lists" aren't lists at all, but lazy machines (generators) waiting to produce data on demand.
Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.
Top comments (0)