Exercises — for loop — iterating over sequences
Level 1 — Recognition (read the loop, predict the output)
You are not writing code yet. You are proving you can trace a loop by hand — pretend you are the computer, holding each item one at a time.
Recall Solution L1.1
The loop hands word each string in order. len(word) counts characters:
"sun"→3"moon"→4"star"→4
Output: 3, 4, 4 (three lines). The body ran 3 times — once per item.
Recall Solution L1.2
range(3) produces 0, 1, 2 — start defaults to 0, stop is excluded. Watch total:
- start:
total = 0 i=0:total = 0 + 0 = 0i=1:total = 0 + 1 = 1i=2:total = 1 + 2 = 3
Output: 3. Only the final value prints, because print is outside the loop.
Recall Solution L1.3
A str is a sequence of characters, so ch visits b, a, n, a, n, a. The vowels are the
three a's. count climbs 0 → 1 → 2 → 3.
Output: 3.
Level 2 — Application (write a loop for a stated task)
Now you produce the loop. State the goal in words first, then translate to a body that runs once per item.
Recall Solution L2.1
nums = [4, 8, 15, 16, 23, 42]
total = 0
for n in nums:
total = total + n
print(total)Why start total = 0? You need a starting accumulator before the loop so the first
addition has something to add to. Running the additions: 4, 12, 27, 43, 66, 108.
Output: 108.
Recall Solution L2.2
words = ["hi", "hello", "hey", "welcome", "yo"]
long_count = 0
for w in words:
if len(w) >= 5:
long_count = long_count + 1
print(long_count)Lengths: 2, 5, 3, 7, 2. Those >= 5 are "hello" (5) and "welcome" (7).
Output: 2.
Recall Solution L2.3
squares = []
for i in range(1, 6): # i = 1, 2, 3, 4, 5
squares.append(i * i)
print(squares)range(1, 6) is half-open [1, 6) → 1, 2, 3, 4, 5. Squaring each: 1, 4, 9, 16, 25.
Output: [1, 4, 9, 16, 25].
Level 3 — Analysis (why does this loop do that?)
Here the code is subtly tricky. Your job is to explain the mechanism, not just the output.
Recall Solution L3.1
The iterator tracks a position number — a counter for "which slot am I on?". Let us call
that counter the cursor, written cur (it starts at 0, the first slot, and Python
advances it by one after each pass). Crucially, the cursor follows the slot, not the value:
when you remove an item, everything after it slides one slot left, but the cursor still
steps to the next slot — so it skips the value that slid into the position it just left.
Trace by slot (cursor cur shown):
cur=0: slot holds1, odd → keep. List[1,2,3,4,5,6]; cursor →cur=1cur=1: slot holds2, even → remove. List becomes[1,3,4,5,6]; cursor →cur=2cur=2: slot holds4(the3slid into slot 1 and was skipped), even → remove. List[1,3,5,6]; cursor →cur=3cur=3: slot holds6, even → remove. List[1,3,5]; cursor →cur=4cur=4: no slot there → loop ends.
Output: [1, 3, 5]. Every other even (4, 6) got removed but the one that slid into
the current slot each time was skipped.
The figure below shows this row by row: each row is the list at one cursor position. The
red slot marks where the cursor currently sits, a yellow outline marks the slot being
removed, and the yellow arrow points to the value 3 that slides into slot 1 and is never
visited. It exists to make the "skip" visible instead of asking you to hold five list states in
your head.
Recall Solution L3.2
zip pairs the i-th items and stops at the shorter sequence. b has only 2 items, so
zip yields exactly two pairs, then raises StopIteration. Items 30 and 40 never get a partner.
Output: [(10, 'x'), (20, 'y')]. This is the whole point of zip — no index arithmetic,
and no IndexError from over-running the short list.
Recall Solution L3.3
for x in prices: iterates the keys, so x becomes "pen", "book", "bag" (strings).
total + x tries to add a string to the integer 0, and Python refuses to add an int and a
str. The exact message is:
TypeError: unsupported operand type(s) for +: 'int' and 'str'
To sum the values, loop prices.values():
for v in prices.values():
total = total + v # 10 + 50 + 200which gives 260.
Level 4 — Synthesis (combine tools to solve a real task)
Multiple loop tools working together. Plan in words, then compose.
Recall Solution L4.1
text = "to be or not to be"
counts = {}
for word in text.split(): # ['to','be','or','not','to','be']
if word in counts:
counts[word] = counts[word] + 1
else:
counts[word] = 1
print(counts).split() breaks the string into a list of words; the for visits each. For each word we
either start its count at 1 or bump the existing count. Tracing: to→1, be→1, or→1, not→1, to→2, be→2.
Output: {'to': 2, 'be': 2, 'or': 1, 'not': 1}.
Recall Solution L4.2
readings = [3, 7, 2, 9, 4, 9, 1]
best_val = readings[0]
best_idx = 0
for i, v in enumerate(readings):
if v > best_val: # strict > keeps the FIRST occurrence
best_val = v
best_idx = i
print(best_val, best_idx)enumerate hands (index, value) pairs so we track both without a manual counter. Using
strict > means a later equal 9 does not overwrite — the first 9 at index 3 wins.
Output: 9 3 → (9, 3).
Recall Solution L4.3
keys = ["a", "b", "c"]
vals = [1, 2, 3]
d = {}
for k, v in zip(keys, vals):
d[k] = v
print(d)zip pairs ("a",1), ("b",2), ("c",3); tuple-unpacking splits each into k and v, and we
assign into the dict. (See Dictionaries — keys, values, items.)
Output: {'a': 1, 'b': 2, 'c': 3}.
Level 5 — Mastery (build the mechanism / control the flow)
Here you demonstrate you understand the engine and the control-flow keywords, not just the plain syntax.
Recall Solution L5.1
A for loop is sugar for exactly this (see the parent note's derivation). Note the
try/except sits inside the while body, indented one level under it:
_it = iter([10, 20, 30]) # 1. get an iterator (cursor at slot 0)
while True: # 2. loop forever...
try: # (this whole try/except is the while body)
x = next(_it) # 3. grab next item, advance cursor
except StopIteration:
break # 4. ...until exhausted -> stop cleanly
print(x) # 5. run the bodyOutput: 10, 20, 30. This is why for never needs off-by-one index counting: the
end is signalled by an exception, not by comparing a counter to a length.
Recall Solution L5.2
items = ["p", "q", "r"]
i = 0
for item in items:
print(i, item)
i = i + 1 # manual counter — exactly what enumerate hides
print("after:", i)The counter i starts at 0, increments once per iteration, and ends at 3 (the number of
items). Output: 0 p, 1 q, 2 r, then after: 3. enumerate does exactly this
bookkeeping for you — that's why it's cleaner.
Recall Solution L5.3
range(2, 7) gives divisors 2, 3, 4, 5, 6. None divide 7 evenly, so the if never fires,
break never runs, and the loop finishes normally. Because no break fired, the else
block runs.
Output: prime. (If n were 9, then d=3 would divide it, print not prime, and
break — so the else would be skipped.)
Recall Solution L5.4
continue jumps to the next item whenever k is even, so total = total + k runs only for
the odd values 1, 3, 5. Adding them: 1 + 3 + 5 = 9.
Output: 9.
Recall Solution L5.5
For each of the 3 values of a, the inner loop runs fully — 2 times. So the body runs
3 times 2 = 6 times. The inner loop finishes before a advances, so pairs come in order:
(0,0), (0,1), (1,0), (1,1), (2,0), (2,1).
Output: 6 lines.
Recall Self-check summary (reveal after attempting all)
Level 1 — Recognition
- L1.1 →
3,4,4 - L1.2 →
3 - L1.3 →
3
Level 2 — Application
- L2.1 →
108 - L2.2 →
2 - L2.3 →
[1, 4, 9, 16, 25]
Level 3 — Analysis
- L3.1 →
[1, 3, 5] - L3.2 →
[(10, 'x'), (20, 'y')] - L3.3 →
TypeError(summingprices.values()would give260)
Level 4 — Synthesis
- L4.1 →
{'to': 2, 'be': 2, 'or': 1, 'not': 1} - L4.2 →
(9, 3) - L4.3 →
{'a': 1, 'b': 2, 'c': 3}
Level 5 — Mastery
- L5.1 → prints
10,20,30 - L5.2 → counter ends at
3 - L5.3 →
prime - L5.4 →
9 - L5.5 →
6iterations
Connections
- Parent: for loop — the concepts drilled here.
- while loop — condition-based repetition — L5.1 desugars
forinto this. - range function — powers L1.2, L2.3, L5.
- Lists and indexing — the sequence behind most exercises.
- Strings as sequences — L1.3 and L4.1
.split(). - enumerate and zip — L3.2, L4.2, L4.3, L5.2.
- Dictionaries — keys, values, items — L3.3, L4.1, L4.3.
- List comprehensions — the safe fix in the L3 mistake.
- Iterators and generators — the
iter/next/StopIterationengine in L5.1.