Control Flow & Functions
Middle Schoolfor vs while and factor repeated code into functions.while loop with no progress toward its exit runs forever.Control flow is the order in which statements execute. By default it is sequential, top to bottom, but two constructs bend it. Selection (if / elif / else) chooses a branch based on a boolean condition. Iteration (while, for) repeats a block. A remarkable theorem — the Böhm–Jacopini structured programming theorem (1966) — proves that sequence, selection and iteration are together sufficient to compute any computable function. You need nothing else.
A function is a named, reusable, parameterised block that takes arguments and returns a value. Functions provide abstraction (hide detail behind a name), reuse (write once, call many times), and scope (variables inside a function are local; they do not leak out). A function's name plus its parameters form its interface; its body is the hidden implementation.
Think of loops as controlled repetition with an invariant — a statement that stays true on every pass. A while loop keeps going until its condition fails; the programmer's duty is to guarantee the condition eventually becomes false, or the loop runs forever (an infinite loop). A for loop iterates a known collection, sidestepping that risk entirely — prefer it whenever the number of steps is known.
Functions are the primary weapon against complexity. A well-named function lets you reason about what it does without re-reading how. This is abstraction: sqrt(2) is meaningful even if you have never read its implementation. Scope enforces the boundary — a variable born inside a function dies when the function returns, keeping the outside world clean and predictable.
Rule of thumb. If you write the same few lines twice, make a function. Duplication is where bugs breed, because a fix applied in one copy silently forgets the other.
We will build a small toolkit: test primality with a loop, and use a while loop with the Collatz sequence — a famous, still-unproven conjecture that every start reaches 1.
def is_prime(n):
if n < 2:
return False # early exit: 0 and 1 are not prime
i = 2
while i * i <= n: # only test up to sqrt(n) (an optimisation)
if n % i == 0: # divisible -> composite
return False
i = i + 1
return True # no divisor found -> prime
def collatz_steps(n):
"""Count steps to reach 1 under the Collatz map (unproven to always halt)."""
steps = 0
while n != 1: # loop invariant: n is a positive integer
if n % 2 == 0:
n = n // 2 # even -> halve
else:
n = 3 * n + 1 # odd -> triple plus one
steps = steps + 1
return steps
# for-loop drives a known range; function calls hide the detail
primes = [n for n in range(2, 30) if is_prime(n)]
print(primes) # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
print(collatz_steps(27)) # 111 steps to reach 1
The i*i <= n test is a genuine algorithmic insight: if n has a divisor larger than its square root, it must also have one smaller, so we can stop early. This single line turns an O(n) check into O(√n).
Q1 When should I use a while loop versus a for loop?
Use for when you know the collection or count of iterations ("do this for each item"). Use while when repetition depends on a condition that may end at an unknown time ("keep going until the user quits"). A for loop cannot accidentally run forever; a while loop can, so it demands a clear termination argument.
Q2 What does it mean that a variable is "local" to a function?
It exists only while the function runs and is invisible outside. Two functions can each use a variable named i without interfering, because each i lives in its own scope. This isolation is what makes functions composable — you can call one without worrying it will trample your variables.
Q3 Is the early return False in is_prime bad style?
No — "guard clauses" that return early on a special case (here, n < 2) often make code clearer than deep nesting. They handle the exception up front and let the main logic proceed unindented. The key is that every path returns a sensible value; the function is still total.
Q4 Why does the Böhm–Jacopini theorem matter practically?
It is the theoretical licence for structured programming: you never need goto or arbitrary jumps. Anything computable can be written with just sequence, if, and loops. That guarantee is why modern languages can safely restrict control flow to a few clean constructs, making programs far easier to read and verify.
How the ideas connect
Every key idea in this chapter, branching from the core concept — use it to see the whole picture at a glance.
The key facts, visualised
Worked problems, step by step
Follow each solution line by line, then try to reproduce it on paper before moving on.
Example 1How many times does this run: for i = 1 to 4: print i?
- i takes 1, 2, 3, 4.
- That is 4 values.
Example 2Trace a function double(n){ return n*2 } called as double(6).
- n is set to 6 in local scope.
- Return 6 * 2.
Now you try
Work each one out first, then tap to reveal the worked answer.