Concepts / Iterating Through Lists with for Loops

Iterating Through Lists with for Loops

Index-based iteration combines range() and len() to generate indices, enabling you to read and modify list elements.

  • Programming
Interactive lab

Try it: Loop Tracer

How a Python for loop visits each item in turn, and how an accumulator variable (a total, a count, a best-so-far or a result list) changes on every iteration.

How it works

  1. Initialise the accumulator before the loop.
  2. Each iteration, the loop variable takes the next value from the list.
  3. An if inside the loop decides whether to update the accumulator.
  4. After the last item the loop ends and the accumulator holds the answer.

Default run (13 steps): values = [4, 9, 2, 7, 5]. Run the loop one statement at a time. … The loop has used every value. print(total) shows 27.

Simplified: A model of five fixed loop programs (sum, count, maximum, minimum, filter) run on your list — it steps the program exactly as Python would, but it does not run Python.

Educational simulation

Loading the simulation…

Interactive lab

Try it: What a for Loop Hands You

What a Python for loop gives its loop variable from each kind of iterable: the characters of a string, the positions from range(len(word)), the elements of a list, (index, item) pairs from enumerate(), the numbers of range(start, stop, step), a dict's keys, its .values() and its .items() tuples unpacked into key, val, the inner lists of a nested list and the values an inner loop visits; and why removing items from a list while looping over it skips the next item, while looping over a copy nums[:] does not.

How it works

  1. The for statement asks the object for an iterator, then calls next() on it once per pass.
  2. Each next() result is bound to the loop variable (a tuple result such as ('a', 10) or (0, 'red') is unpacked into two names), and the indented body runs once with it.
  3. A string gives characters, a list gives element values (not positions), range() computes start, start + step, … stopping before stop, and a dict gives its keys in insertion order (.values() the values, .items() key-value tuples).
  4. A nested list's inner list is one element of the outer loop; a second, inner for loop is needed to visit the values inside it.
  5. A list iterator only remembers a position number into the live list: removing an item shifts the later items left, so the item that slides into the passed position is skipped. Looping over a copy (nums[:]) keeps the positions fixed.
  6. When next() has nothing left the loop ends (StopIteration) and the loop variable keeps its last value; an empty iterable runs the body zero times.

Default run (10 steps): A 3-line program. Step through it: each pass of the for loop asks the iterator for its next item, binds the loop variable to it and runs the indented body once. … Done: the loop body ran 3 times. Output: red | green | blue.

Simplified: The programs are twelve fixed templates: you choose the loop and edit only its data (a short string, list items that are words or integers, key: value pairs with word keys and integer values, range numbers from -20 to 20, up to 4 rows of integers, up to 10 numbers). Nothing you type is executed: the lab's own small parsers turn it into literals, and a model of CPython's iterator protocol written for these loops runs the program. Every program was also run in CPython 3.12 under sys.settrace, and the lab reproduces the variables before every line, the printed output, the final variables and the error.

Educational simulation

Loading the simulation…

Why the Index Matters

A for loop can move through a list by using the list's values, but some tasks require the position of each value as well. Index-based iteration combines range() and len() to generate indices. Those indices let a loop locate a list element, read its current value, and assign a new value back to that same position.

What do you think happens?

Suppose a loop uses the assignment numbers[i] = numbers[i] * 2. What does the statement do at the current index?

  • It reads the current value and writes a new value at the same position

  • It only reads the value and leaves the list unchanged

  • It removes the current element from the list

Reveal answer
Answer:

It reads the current value and writes a new value at the same position

The expression on the right reads the old value at index i, multiplies it by 2, and the assignment writes the result back to index i.

Mapping Indices to Elements

The expression len(list) supplies the list length, and range(len(list)) is used to generate the indices needed for the loop. The loop variable represents the current index. Writing list[i] then refers to the element at that position, so the same index can be used to inspect or update the corresponding list element.

0first positionnumbers[0]first element1second positionnumbers[1]second element2third positionnumbers[2]third elementselectsselectsselects
Which generated index is paired with each list element?
python

Reading and Reassigning

Worked example

Doubling Each Element

Trace the assignment numbers[i] = numbers[i] * 2 as the loop processes a list.

  1. 1
    Read

    At the current index i, numbers[i] on the right side supplies the old value.

  2. 2
    Calculate

    The old value is multiplied by 2.

  3. 3
    Assign

    The result is written to numbers[i], replacing the old value at the same position.

Result

Each processed element receives a new value equal to its old value multiplied by 2.

old valuenumbers[i]multiply by 2numbers[i] * 2new valuenumbers[i]readwrite
How does the value at the current index move from its old state to its new state?

The two appearances of numbers[i] have different roles. On the right side, numbers[i] is read as the old value. On the left side, numbers[i] identifies where the calculated result is written. This is why one assignment can both inspect and update the current list element.

Following the Loop Flow

len(numbers)list lengthrange(len(numbers))generated indicescurrent index iselect positionnumbers[i]read or update elementnext indexcontinue loopsupplies lengthprovidesselectsthen
What happens as an index-based loop obtains the list length, selects an index, accesses an element, and advances?

A useful trace follows the loop in order: determine the list length, use range(len(list)) to provide indices, use the current index to access the element, perform the read or update, and then continue to the next generated index. Tracing makes the final list state predictable instead of treating the loop as one unexplained action.

Tracing Every Update

numbers[1, 2, 3]i = 0[2, 2, 3]i = 1[2, 4, 3]i = 2[2, 4, 6]final numbers[2, 4, 6]update index 0update index 1update index 2loop complete
What is the list's state before and after each update, and what final list results?
Worked example

Predicting the Final List

Start with numbers = [1, 2, 3] and apply numbers[i] = numbers[i] * 2 during each iteration.

  1. 1
    Initial state

    The list begins as [1, 2, 3].

  2. 2
    First update

    The current element has value 1. Multiplying it by 2 changes the list to [2, 2, 3].

  3. 3
    Second update

    The current element has value 2. Multiplying it by 2 changes the list to [2, 4, 3].

  4. 4
    Third update

    The current element has value 3. Multiplying it by 2 changes the list to [2, 4, 6].

Result

The final list is [2, 4, 6].

The important tracing habit is to record the list after every assignment. Only the element at the current index changes during that step. Previously updated elements keep their new values, while elements not yet reached still have their old values.

Choosing the Loop Style

Loop purposePreferred approachReason
Read list elementsValue-based iterationUse this when the values only need to be inspected.
Update list elementsIndex-based iteration with range() and len()Use the index to write a new value back to the element's position.

Choose the loop form based on whether the list must be changed.

list valuesread onlyindex iselect positionlist elementwrite new valuelocates
What changes when a loop only reads values compared with when it must update list elements?

Mistakes in Loop Traces

  • Common mistake

    Treating numbers[i] on the right side as the new value

    What it looks like
    numbers[i] = numbers[i] * 2
    Why it fails

    The right side is evaluated first, so numbers[i] supplies the old value before the assignment replaces the element.

    Do this instead

    Trace the statement as read the old value, multiply it by 2, then write the result to the same index.

  • Common mistake

    Choosing value-based iteration when the list must be updated

    What it looks like

    A loop reads each value but does not use an index to assign a result back to the list.

    Why it fails

    Updating an element requires identifying its position so a new value can be written there.

    Do this instead

    Use index-based iteration with range() and len() when elements must change.

  • Common mistake

    Skipping intermediate list states

    What it looks like

    Jumping directly from the original list to the final list.

    Why it fails

    Without tracing each index, it is easy to lose track of which elements have already changed.

    Do this instead

    Write the list after every assignment and identify the current index at each step.

EASY

Trace an index-based loop that applies numbers[i] = numbers[i] * 2 to the list [4, 5]. Record the list after each update and state the final list.

Hints
  • Identify the current index for the first update.
  • Read the old value at that index before multiplying it.
  • Write the changed list before moving to the next index.

Key Takeaways

  1. 1
    range(len(list)) combines the list length with range() to generate indices for an index-based loop.
  2. 2
    list[i] can be read on the right side of an assignment and written on the left side of the same assignment.
  3. 3
    The statement numbers[i] = numbers[i] * 2 reads the old value and writes the doubled value back to the same position.
  4. 4
    Use value-based iteration for reading values and index-based iteration when list elements must be updated.
  5. 5
    Tracing each index and intermediate list state reveals the final state of the list.

At a glance

  • Use range(len(list)) to generate indices for iterating through a list by position.
  • An assignment such as numbers[i] = numbers[i] * 2 reads the old element and writes a new value to the same index.
  • Choose value-based iteration for reading and index-based iteration for updating list elements.
  • Trace each iteration and record the list state after every assignment to predict the final result.

Related concepts

More concepts starting with I