Control Flow
So far every program has run top to bottom. Control flow lets it choose and repeat, which is where programs stop being calculators and start being algorithms — and where indentation stops being cosmetic and starts being syntax.
- Write correct
if/elif/elsechains. - Choose between
forandwhiledeliberately. - Trace nested loops and predict the output.
- Diagnose an infinite loop and an off-by-one error.
A fixed sequence of steps can only ever do one thing. Branching and repetition are what let a fixed-length program handle inputs of any size, which is the whole idea of an algorithm.
Every retry policy, every rate limiter, every game loop is control flow. The 2012 Knight Capital loss of $440 million in 45 minutes was a stale branch condition sending orders nobody intended.
Dijkstra's 1968 letter "Go To Statement Considered Harmful" argued that
unrestricted jumps make programs impossible to reason about. Python has no
goto at all, which is that argument having won.
Conditionals
An if statement runs its block when the condition is truthy.
elif chains additional tests; else catches
everything remaining. At most one branch of a chain ever runs.
def grade(mark: int) -> str:
"""Return the letter grade for mark."""
if mark >= 80:
return 'A'
elif mark >= 70:
return 'B'
elif mark >= 60:
return 'C'
else:
return 'F'85 returns 'A' and never reaches the
70 test.>= 60
first, every passing mark returns 'C'. Chains must go from most
to least restrictive.Replacing elif with if makes each test run
independently. With return inside, the behaviour happens to
match; without it, several branches execute and the last one wins. Use
elif when the cases are meant to be exclusive.
Python treats as false: False, None,
0, 0.0, '', [],
{}. Everything else is true. So if items: reads as
"if the list is non-empty", which is the idiomatic emptiness test —
prefer it to if len(items) > 0:.
Loops
for when you know what you are iterating over
— a list, a string, a range. This is the default in Python.while when you are waiting for a condition and
cannot say in advance how many rounds it takes.If you find yourself writing while i < len(xs) with a
manual counter, you wanted a for.
# idiomatic: iterate the values
total = 0
for x in nums:
total = total + x
# by index, when you need the position too
for i in range(len(nums)):
total = total + nums[i]
# both at once
for i, x in enumerate(nums):
print(i, x)Reach for the first form unless the index is genuinely needed. Marks in this course go to the version that says what it means.
range(5) # 0 1 2 3 4 - stop only range(2, 5) # 2 3 4 - start, stop range(2, 11, 3) # 2 5 8 - start, stop, step range(5, 0, -1) # 5 4 3 2 1 - counting down
The stop value is always excluded. That single convention is behind most
off-by-one errors, and it is also why
range(len(xs)) gives exactly the valid indices.
for i in range(3):
for j in range(2):
print(i, j)0 0, 0 1,
1 0, 1 1, 2 0, 2 1.break, continue, and the loop that will not end
break exits the innermost loop immediately.
continue skips to the next iteration. Both apply only to the
loop directly containing them.
def first_negative(nums: list) -> int:
"""Return the first negative value in nums, or 0 if there is none."""
for x in nums:
if x < 0:
return x
return 0Returning from inside the loop is cleaner than break plus a
flag variable. Once the answer is known, leave.
• Nothing in the body changes the condition.
• The change moves the wrong way, so the condition never becomes
false.
• The condition tests a float for exact equality, and floating point
steps past it — see Unit 10.
If a program hangs, interrupt it and read which line it stopped on. That is almost always inside the offending loop.
• Mixing tabs and spaces. Python counts indentation as syntax; set the
editor to spaces only.
• Forgetting the colon after if, for,
while, def.
• Modifying a list while iterating over it. Items get skipped; iterate a
copy with for x in xs[:] or build a new list.
• Comparing with and/or incorrectly:
if x == 1 or 2: is always true, because 2 is truthy.
Write if x == 1 or x == 2: or if x in (1, 2):.
Practice
Predict each answer before running it. Original exercises written for this guide in the style of the course's weekly sets.
How many lines does for i in range(2, 10, 3) print?
Answer
2,
5, 8. The next would be 11, past the
excluded stop.What does grade(85) return if the chain tests
>= 60 first?
Answer
'C'. The
first true test wins, so a loose test placed early swallows everything
above it.How many times does the inner body run?
for i in range(4):
for j in range(i):
print(i, j)Answer
i, so the count is a
triangular number rather than a product.Write a function returning True if a list is sorted
ascending.
Solution
def is_sorted(xs: list) -> bool:
"""Return whether xs is in non-decreasing order.
>>> is_sorted([1, 2, 2, 5])
True
"""
for i in range(len(xs) - 1):
if xs[i] > xs[i + 1]:
return False
return Truelen(xs) - 1: comparing each item to its successor means
stopping one early. An empty or one-item list correctly returns
True.Why does this never end, and what is the fix?
n = 10
while n != 0:
n = n - 3Answer
n takes
values 10, 7, 4, 1, -2, ... and skips 0 entirely. Test
while n > 0: instead. Prefer inequality to equality when
stepping by anything other than one.What goes wrong here?
for x in xs:
if x < 0:
xs.remove(x)Answer
[-1, -2, 3] the -2
survives. Build a new list:
xs = [x for x in xs if x >= 0].Which loop suits reading input until the user types
quit?
Answer
while. The
number of rounds is unknown in advance, which is exactly the case
while exists for.Print 1 to 15, replacing multiples of 3 with Fizz, of 5 with Buzz, of both with FizzBuzz.
Solution
for n in range(1, 16):
if n % 15 == 0:
print('FizzBuzz')
elif n % 3 == 0:
print('Fizz')
elif n % 5 == 0:
print('Buzz')
else:
print(n)% 15 first is the whole trick: the most restrictive
case has to come before the cases it also satisfies.Expanded topic checklist
Course coverage. This unit is part of the complete CSC108H1 topic map. It should cover the following items before you move on:
- Conditionals. if/elif/else, chain ordering, and truthiness.
- Loops. for over a sequence, while on a condition, and when each is right.
- range. All three forms and the excluded stop.
- Loop control. break, continue, early return, and diagnosing infinite loops.
The calendar lists "program structure: control flow" immediately after the elementary types. Check the syllabus on Quercus for the week this lands and for the assigned exercises.
Conditions choose; loops repeat; both are delimited by indentation. Unit 3 wraps these in functions so they can be named, tested and reused.
Deep practice extensions
Use these after the main practice set. They push on definitions and edge cases rather than routine calculation.
How many branches of an if/elif/else chain run?
Guide
else if none is.Why does range(len(xs)) give valid indices?
Guide
When is while the right choice?
Guide
Two nested loops over $n$ items do how many iterations?