List Mutability and In-Place Modifications
Tracing means recording the list after each assignment, not only calculating the final answer. At every step, one position receives a new value while the other positions retain their current values.
A List That Changes While It Runs
Suppose a list contains numbers and your goal is to replace every number with its doubled value. The loop must reach each element, read its current value, calculate a replacement, and store that replacement in the same list position. This is an in-place modification: the list is updated as the loop runs.
What do you think happens?
If a loop doubles every element in the list [3, 5, 7], what list should remain after all iterations?
Reveal answer
[6, 10, 14]
Each element is read and replaced by its doubled value. The loop changes the list one position at a time.
From Length to Valid Indices
Index-based iteration combines range() and len(). len(my_list) supplies the list's length, and range(len(my_list)) supplies the sequence of indices used to reach the list elements. The loop variable therefore represents a position, not the element's value itself.
0 3
1 5
2 7Reading and Replacing One Position
The statement numbers[i] = numbers[i] * 2 performs two related actions. The expression on the right reads the old value at index i and multiplies it by 2. The assignment on the left writes the resulting new value back to that same position.
[6, 10, 14]Tracing Every Iteration
Doubling Each Element
Trace the loop for numbers = [3, 5, 7] and determine the final list.
- 1Start
The list begins as [3, 5, 7].
- 2First index
At the first index, the current value is 3. The loop stores 3 multiplied by 2 in that position, so the list becomes [6, 5, 7].
- 3Second index
At the next index, the current value is 5. The loop stores 5 multiplied by 2 in that position, so the list becomes [6, 10, 7].
- 4Third index
At the final index, the current value is 7. The loop stores 7 multiplied by 2 in that position, so the list becomes [6, 10, 14].
The final state of the list is [6, 10, 14].
Tracing means recording the list after each assignment, not only calculating the final answer. At every step, one position receives a new value while the other positions retain their current values.
Choosing the Loop Style
| Iteration style | What the loop provides | Use it when |
|---|---|---|
| Value-based iteration | Each list value directly | You only need to read the elements |
| Index-based iteration | An index used to reach each element | You need to update elements in the list |
Choose based on whether the loop only reads values or must write replacements into the list.
If the task is only to inspect or read each value, value-based iteration is sufficient. If the task requires replacing elements, index-based iteration provides the position needed for an assignment such as numbers[i] = numbers[i] * 2.
Mistakes in In-Place Updates
Common mistake Using a loop that only supplies values when the task requires replacing list elements.
What it looks likeThe loop can read a value, but the assignment still needs a list position to identify where the replacement belongs.
Why it failsValue-based iteration is suitable for reading, whereas updating requires index-based access.
Do this insteadUse range(len(numbers)) and assign to numbers[i].Common mistake Reading the old value but not assigning the calculated value back to the list.
What it looks likeCalculating a doubled value without a statement of the form numbers[i] = numbers[i] * 2.
Why it failsA calculation alone does not write the replacement into the list position.
Do this insteadPut the original value on the right side and the indexed list position on the left side of the assignment.
Common mistake Predicting the final list without tracing the intermediate states.
Why it failsThe loop changes one targeted position at a time, so each iteration can be checked separately.
Do this insteadRecord the list before the loop and after each index is processed.
Practice the Trace
Trace this loop without running it. Write the list after each iteration and then give the final state: values = [4, 1, 6]; for i in range(len(values)): values[i] = values[i] * 2
Hints
- Use
range(len(values))to identify each index in order. - At each index, read the current value and replace it with that value multiplied by 2.
- Write the whole list after the update at each position.
A reliable trace has three parts: identify the current index, read the value at that index, and write the replacement back to the same index. Repeating those three actions produces the final list state.
What to Remember
- 1
range(len(my_list))combines the list length with a generated sequence of indices for index-based iteration. - 2numbers[i] = numbers[i] * 2 reads the old value at index i and writes a new value back to that same position.
- 3Use value-based iteration when you only need to read list elements.
- 4Use index-based iteration when you need to update list elements.
- 5Trace the list after each iteration to predict its final state.
At a glance
range()andlen()work together to provide indices for traversing a list by position.- An indexed assignment can read an element's old value and replace it in the same position.
- Index-based iteration is appropriate for updates; value-based iteration is appropriate for reading.
- Tracing each intermediate list state makes the final result predictable.