Iterating Over Strings with for Loops
A for loop executes a block of code once for each element in a list, with the loop variable taking on each element's value in sequence.
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
- The for statement asks the object for an iterator, then calls next() on it once per pass.
- 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.
- 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).
- 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.
- 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.
- 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.
Loading the simulation…
One Instruction, Many Characters
Suppose you want to display every character in a word. You could handle each character separately, but a for loop lets you write the processing instruction once and run it for every character. When Python traverses a string with a for loop, it automatically assigns one character at a time to a loop variable.
b
a
n
a
n
aWhat do you think happens?
Before reading the explanation, predict how many times print(char) runs and what char contains on the first and last iterations.
Reveal answer
print(char) runs six times. char contains b on the first iteration and a on the last iteration.
The string banana has six characters. The loop visits them in order, assigning one character to char during each iteration.
Positions Become Iterations
The string banana contains six characters. Their positions correspond to the order in which the loop receives them: b first, then a, then n, then a, then n, then a. The loop variable receives the character itself rather than displaying the position number. You do not manually write an index, increment a counter, or check whether the end of the string has been reached.
A for loop is simpler and more readable than manually traversing a string with a while loop and index tracking. The loop makes the intention clear: visit every character in order. It also avoids having to remember to increment an index or check whether the end of the string has been reached.
Following the Loop Variable
To trace a loop, record the loop variable's value at every iteration and then record what the loop body does with that value. In the example below, char is reassigned as control moves through fruit. It does not keep all the characters at once; it holds the current character for the current iteration.
Adding a Message Around Each Character
Trace what happens when each character in the string code is printed with a label.
- 1First iteration
char receives c. The loop body prints Character: c.
- 2Second iteration
char receives o. The loop body prints Character: o.
- 3Third iteration
char receives d. The loop body prints Character: d.
- 4Fourth iteration
char receives e. The loop body prints Character: e.
- 5After the loop
All four characters have been visited, so execution continues with the next unindented statement.
The loop body runs four times, once for each character, in the order c, o, d, e.
Character: c
Character: o
Character: d
Character: e
FinishedInside and After the Loop
Indentation determines which statements belong to the loop body. A statement indented under the for statement runs once for every character. A statement at the original indentation level runs after the loop has processed all characters. This difference controls whether an action repeats or happens only once.
word = "go"
for char in word:
print(char)
print("Finished")Finished is indented, so it runs once for each character.
word = "go"
for char in word:
print(char)
print("Finished")Finished is not indented under the loop, so it runs after both characters have been processed.
Naming the Current Character
The loop variable name is arbitrary. In a string loop, names such as char or letter can indicate that the variable holds one character. A descriptive name makes the loop self-documenting. A short name may work, but it gives the reader less information about the value being processed.
| Loop form | Value received by the loop variable | Readability |
|---|---|---|
| for char in fruit | One character from fruit | Descriptive |
| for letter in fruit | One character from fruit | Descriptive |
| for f in fruit | One character from fruit | Less clear |
Different loop variable names can work identically, but descriptive names communicate intent more clearly.
Mistakes During Traversal
Common mistake Forgetting to indent the loop body.
What it looks likefor char in word: print(char)Why it failsThe statement intended to run for each character is not indented under the for statement.
Do this insteadIndent the loop body so Python can identify it as part of the loop.
Common mistake Indenting code that should run after the loop.
What it looks likefor char in word: print(char) print("Finished")Why it failsFinished is inside the loop, so it runs once per character rather than once after all characters.
Do this insteadPlace the final print statement at the original indentation level.
Common mistake Using the wrong variable name inside the loop.
What it looks likefor char in word: print(letter)Why it failsThe loop assigns characters to char, not letter.
Do this insteadUse the same loop variable name in the body, such as print(char).
Common mistake Expecting the loop variable to contain an index number.
What it looks likefor char in "banana": print(char)Why it failsA string loop gives the loop variable each character directly. It does not display the position number.
Do this insteadTreat char as the current character and trace the characters in their string order.
Repeated characters are still visited separately. In banana, the loop receives a, n, and a at different iterations. The loop does not remove or skip a character merely because the same character appeared earlier.
When the output differs from your expectation, write the string's characters in order and place one character beside each iteration. Then check three points: whether every character appears in the expected order, whether the loop variable name matches the name used in the body, and whether each statement has the intended indentation.
Practice the Trace
Write a for loop that traverses the string "lamp". For each character, print the text "Current:" followed by the character. Then print "All done" only after the loop completes.
Hints
- Use a descriptive loop variable such as char.
- Place the repeated print statement inside the loop.
- Place the final print statement at the original indentation level.
Trace this loop without running it. Write the value of letter and the output produced on each iteration: word = "tree"; for letter in word: print(letter). Then explain why the repeated e characters produce two separate iterations.
Hints
- List the characters from left to right.
- The loop variable receives one character during each iteration.
- Repeated characters remain separate positions in the traversal.
A reliable trace follows the same pattern every time: identify the next character, assign it mentally to the loop variable, execute the indented body, and then move to the next character. After the final character, stop repeating the indented body and continue with the unindented code.
Key Takeaways
- 1A for loop over a string assigns each character to its loop variable in sequence.
- 2The loop body runs once for every character, while unindented code runs after the loop completes.
- 3Tracing the loop variable step by step helps you predict output and locate unexpected behavior.
- 4The loop variable name can be chosen freely, but a descriptive name makes the code easier to understand.
- 5A for loop handles the traversal automatically, so manual index tracking is not required.
At a glance
- A string for loop visits characters from first to last.
- The loop variable holds the current character and changes on each iteration.
- Indentation separates repeated loop-body work from work that happens after the loop.
- Tracing each character and output is an effective way to predict results and debug loops.
- Descriptive loop variable names improve readability.