Kiru Lab / Foundations: Python as an Instrument / Python From First Principles
Repeating Work
Loops — the construct that turns a small amount of arithmetic into a trained model.
Code Walkthrough · about 35 minutes
A `for` loop runs a block once for each item in a collection. A `while` loop runs it until a condition stops being true. Between them, these two account for essentially all repetition in this curriculum — including every training loop you will ever write.
for token in ["the", "model", "learns"]:
print(token.upper())
for i in range(5): # 0, 1, 2, 3, 4 — stops before 5
print(i)
for i, token in enumerate(["a", "b", "c"]): # index and value together
print(i, token)
for name, score in zip(["a", "b"], [0.9, 0.7]): # two collections in step
print(name, score)error = 10.0
steps = 0
while error > 0.001:
error = error * 0.5
steps = steps + 1
if steps > 1000: # always give a while loop an escape hatch
print("did not converge")
break
print(f"converged in {steps} steps")That second example is the shape of every iterative solver in this lab. The inverse kinematics routine in track six is exactly this loop with a Jacobian inside it, and the same 1000-iteration safety cap for exactly the same reason.
Accumulating a result
losses = [] # start empty
for epoch in range(10):
loss = train_one_epoch() # do the work
losses.append(loss) # collect the result
average = sum(losses) / len(losses)break and continue
- `break` leaves the loop entirely — use it when you have found what you were looking for.
- `continue` skips to the next iteration — use it to filter out cases you do not want to process.
- A loop with several `break` points is usually a function that wants extracting.
In the next module you will learn to replace loops like these with array operations that run a hundred times faster. Write the loops first anyway. You cannot vectorize an operation you could not write out by hand, and when a vectorized line misbehaves the loop is how you check it.
Hold on to
- for when you know the collection; while when you know the condition
- Always give a while loop an iteration cap
- Initialize, iterate, accumulate — the shape of every training loop
Work through
Try each one before opening the solution. Getting it wrong first is most of where the learning happens.
-
Write a loop that sums the numbers 1 to 100 and prints the total. Then do it with `sum(range(...))` and confirm the answers match.
Hint
`range(1, 101)` stops before 101.
Solution
Both give 5050. Reach for the built-in in real code — it is faster and clearer — but write the loop at least once so you know what the built-in is doing.
total = 0 for n in range(1, 101): total += n print(total) # 5050 print(sum(range(1, 101))) # 5050Check your work
Paste this after your own code. If it runs without raising, you have it.
assert sum(range(1, 101)) == 5050 print("ok") -
Write the halving loop from the lesson as a function `steps_to_converge(start, target)`, and report how many steps it takes to get from 10.0 below 1e-6.
Hint
Count iterations in a variable you increment inside the loop.
Solution
It takes 24 steps: halving from 10.0, you need 10 * 0.5**n < 1e-6, so n > log2(10^7) which is about 23.3. Keep the iteration cap — an unbounded while loop with a condition that can never be satisfied is an infinite hang, and you will write one eventually.
def steps_to_converge(start, target, max_steps=1000): value, steps = start, 0 while value > target: value *= 0.5 steps += 1 if steps >= max_steps: raise RuntimeError("did not converge") return stepsCheck your work
Paste this after your own code. If it runs without raising, you have it.
assert steps_to_converge(10.0, 1e-6) == 24 assert steps_to_converge(1.0, 0.5) == 1 print("ok") -
Using `enumerate`, print each word of a sentence with its position, but skip any word shorter than four letters. Use `continue` rather than nesting an if.
Hint
`continue` jumps to the next iteration without running the rest of the body.
Solution
Test the skip condition first and `continue`, which leaves the interesting work unindented. This is the loop version of the guard clause, and it reads better than wrapping the body in an `if len(word) >= 4:`.
sentence = "the model learns a compressed map of its training data" for i, word in enumerate(sentence.split()): if len(word) < 4: continue print(i, word)
Sign in to track your progress through the lab.