Unit 2 · 5 teaching hours · 19 min read
Control Flow
What the syllabus asks for 8
- Conditional statements
- The while loop
- The for loop and range
- break, continue, pass and loop else
- Nested loops and patterns
- Classic programs
- Common mistakes
- Seeing the ideas: choices, loops and a very long trip
A program that runs line by line from top to bottom can only do one thing. Control flow lets it choose (if), repeat (while, for), and leave a loop early (break). With these three ideas plus variables you can express any algorithm.
- Conditional statements:
if,elif,else, conditional expressions,match. - Loops:
while,for,range,break,continue, loopelse, nested loops. - Classic algorithms: primes, GCD, factorial, Fibonacci, digit sums, number patterns.
2.1 Conditional statements
marks = 67
if marks >= 80:
grade = "Distinction"
elif marks >= 60:
grade = "First division"
elif marks >= 45:
grade = "Second division"
else:
grade = "Fail"
print(marks, "->", grade)
67 -> First division
Only the first true branch runs. The colon and the indentation are mandatory. A conditional expression gives a value in one line: status = "pass" if marks >= 40 else "fail". Conditions can be chained (0 <= marks <= 100) and combined with and, or, not.
def classify(n):
if n < 0:
return "negative"
if n == 0:
return "zero"
return "even" if n % 2 == 0 else "odd"
for n in (-4, 0, 7, 10):
print(n, classify(n), "pass" if n >= 5 else "fail")
-4 negative fail
0 zero fail
7 odd pass
10 even pass
Structural pattern matching (Python 3.10+)
match compares a value against patterns; _ is the wildcard.
def describe(command):
match command.split():
case ["go", direction]:
return f"moving {direction}"
case ["take", item, *rest]:
return f"taking {item} (+{len(rest)} more words)"
case ["quit"]:
return "bye"
case _:
return "unknown command"
for c in ("go north", "take lamp and key", "quit", "dance"):
print(c, "->", describe(c))
go north -> moving north
take lamp and key -> taking lamp (+2 more words)
quit -> bye
dance -> unknown command
2.2 The while loop
A while loop repeats as long as its condition is true. Make sure something in the body eventually makes the condition false.
n, steps = 27, 0
while n != 1:
n = n // 2 if n % 2 == 0 else 3 * n + 1
steps += 1
print("Collatz steps for 27:", steps)
total, k = 0, 1
while total < 100:
total += k
k += 1
print("first k with 1+2+...+k >= 100:", k - 1, "sum", total)
Collatz steps for 27: 111
first k with 1+2+...+k >= 100: 14 sum 105
2.3 The for loop and range
A for loop iterates over any iterable (list, string, tuple, dict, file, range). range(stop), range(start, stop) and range(start, stop, step) produce integers up to, but not including, stop.
for ch in "BCA":
print(ch, end=" ")
print()
print(list(range(5)), list(range(2, 9, 3)), list(range(10, 0, -3)))
total = 0
for i in range(1, 11):
total += i * i
print("sum of squares 1..10 =", total)
for i, name in enumerate(["Ram", "Sita", "Hari"], start=1):
print(i, name)
B C A
[0, 1, 2, 3, 4] [2, 5, 8] [10, 7, 4, 1]
sum of squares 1..10 = 385
1 Ram
2 Sita
3 Hari
Prefer for when the number of repetitions is known or you are walking a collection; prefer while when you loop until some condition changes.
2.4 break, continue, pass and loop else
breakleaves the innermost loop immediately.continueskips to the next iteration.passdoes nothing (a placeholder for an empty block).- A loop's
elseclause runs only if the loop finished withoutbreak.
def is_prime(n):
if n < 2:
return False
for d in range(2, int(n ** 0.5) + 1):
if n % d == 0:
return False
return True
print([n for n in range(2, 40) if is_prime(n)])
for n in (91, 97):
for d in range(2, n):
if n % d == 0:
print(n, "is composite: divisible by", d)
break
else:
print(n, "is prime")
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
91 is composite: divisible by 7
97 is prime
(91 = 7 × 13 is composite, so the loop is ended by break and its else clause is skipped; 97 completes the loop and prints "is prime".) Loop else is the neat way to express "search failed".
2.5 Nested loops and patterns
for row in range(1, 5):
print(" " * (4 - row) + "*" * (2 * row - 1))
print()
for i in range(1, 4):
print(" ".join(f"{i * j:2d}" for j in range(1, 6)))
*
***
*****
*******
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
The inner loop runs completely for every iteration of the outer loop, so two nested loops of size n do about n² steps.
2.6 Classic programs
# gcd by Euclid's algorithm, factorial, Fibonacci, digit sum, palindromes
a, b = 252, 105
while b:
a, b = b, a % b
print("gcd(252, 105) =", a)
f = 1
for i in range(2, 11):
f *= i
print("10! =", f)
x, y, fib = 0, 1, []
for _ in range(12):
fib.append(x)
x, y = y, x + y
print(fib)
n, s = 98765, 0
while n:
s += n % 10
n //= 10
print("digit sum:", s, "| palindrome check:", str(12321) == str(12321)[::-1])
gcd(252, 105) = 21
10! = 3628800
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
digit sum: 35 | palindrome check: True
# number guessing with a fixed 'secret' and a scripted list of guesses
secret = 37
for attempt, guess in enumerate([50, 25, 37], start=1):
if guess < secret:
print(attempt, guess, "too low")
elif guess > secret:
print(attempt, guess, "too high")
else:
print(attempt, guess, "correct!")
break
1 50 too high
2 25 too low
3 37 correct!
2.7 Common mistakes
- Using
=where==is meant in a condition (Python reports aSyntaxError, which helps). - Forgetting that
range(1, 10)stops at 9. - An infinite
whileloop because the loop variable is never updated. - Modifying a list while iterating over it; iterate over a copy or build a new list.
- Comparing floats for equality.
2.8 Seeing the ideas: choices, loops and a very long trip
Every program is built from three moves: go straight, choose a branch, and go round again. A fork in a road is the plainest picture of a choice, and the plate pairs one with the grade ladder that a Python if, elif and else follows.
The figures then show how long a while loop can run when you cannot guess the count, and how break, continue and the loop else change the path.

n, steps, peak = 27, 0, 27
while n != 1:
n = n // 2 if n % 2 == 0 else 3 * n + 1
steps += 1
peak = max(peak, n)
print(steps, peak)
111 9232
Nested loops and while loops are easiest to trust after you have counted what they do. The two plates below run the loops for real and report the counts.


2.8.1 Eight good habits when writing conditions and loops
- Test the most specific case first. In an
if/elifchain Python stops at the first true test, somarks >= 40placed beforemarks >= 80would give every student only a pass. Write the strictest condition at the top and the general one last. Read the chain once from the top as a check before you run it. - Use
elif, not many separateiflines, for exclusive choices. Separateifstatements are all tested, which wastes time and can print two answers for one input. Anelifchain runs exactly one branch. A ConnectIPS fee-slab program is a good example of one value falling into exactly one slab. - Prefer
forwhen the sequence is known andwhilewhen it is not.for subject in subjects:cannot run forever, while awhileloop that forgets to change its variable can. Usewhilefor input validation or for repeating until a goal is reached. This one choice removes most infinite-loop bugs. - Always change the loop variable in a
whileloop. The condition must be able to become false, so something inside the body must move towards that. A missingi += 1is the most common cause of a program that seems to hang. Press Ctrl+C to stop it, then add the update. - Use
rangeandenumerateinstead of counting by hand.for i, name in enumerate(names, start=1):gives both the position and the item and cannot go out of range. It is shorter thanrange(len(names))and easier to read. A roll-number list printed from 1 is a typical use. - Do not change a list while you loop over it. Removing items from the list you are walking over skips elements, because the positions shift. Loop over a copy such as
for x in items[:]:or build a new list with a comprehension. This avoids a bug that does not produce any error message. - Keep nesting shallow. A loop inside a loop inside an
ifis hard to read, and its running time grows as n x n. Usecontinueto skip unwanted cases early, or move the inner part into a function. Two levels are fine for patterns and tables; more deserves a function. - Use loop
elseandbreakfor searches. Instead of a flag variable such asfound = False, put the failure message in theelseof theforloop. The code is shorter and shows the intent: "if no break happened, nothing was found". The weakness is that many beginners do not know this feature, so add a comment.
Formula and fact sheet
if / elif / else: first true branch only.x if cond else yis an expression.while cond:repeats while true.for x in iterable:walks a sequence.range(start, stop, step)excludesstop.breakexits;continueskips; loopelseruns if nobreak.- Euclid:
while b: a, b = b, a % b.
Chapter summary
if/elif/elseandmatchchoose among alternatives; conditions use comparison and logical operators.whilerepeats until a condition fails;foriterates over iterables;rangegenerates integer sequences.break,continue,passand loopelsefine-tune loops; nested loops cost the product of their sizes.- Classic algorithms (primes, GCD, factorial, Fibonacci, digit sums) are all small loops.
Practice
- Write a program that prints the grade for marks using the TU scale (≥ 80 Distinction, ≥ 60 First, ≥ 45 Second, ≥ 40 Pass, else Fail) for marks 85, 62, 47, 41, 12.
- Explain the difference between
breakandcontinuewith a short program that prints odd numbers up to 9 but stops at 7. - Print all primes below 50.
- Compute the sum of the digits and the reverse of 4096.
- Print the first ten terms of the Fibonacci series.
- What does the loop
elsedo? Show an example of a search that uses it. - Print this pattern for n = 4: a right triangle of
#with 1, 2, 3, 4 symbols.
Answers and worked solutions
1.
def grade(m):
if m >= 80: return "Distinction"
if m >= 60: return "First"
if m >= 45: return "Second"
if m >= 40: return "Pass"
return "Fail"
for m in (85, 62, 47, 41, 12):
print(m, grade(m))
85 Distinction
62 First
47 Second
41 Pass
12 Fail
2. break ends the loop; continue skips only the current iteration.
for n in range(1, 10):
if n % 2 == 0:
continue
if n > 7:
break
print(n, end=" ")
print()
1 3 5 7
3.
print([n for n in range(2, 50) if all(n % d for d in range(2, int(n ** 0.5) + 1))])
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
4.
n, s, rev = 4096, 0, 0
while n:
s += n % 10
rev = rev * 10 + n % 10
n //= 10
print("sum", s, "reverse", rev)
sum 19 reverse 6904
5.
a, b = 0, 1
out = []
for _ in range(10):
out.append(a)
a, b = b, a + b
print(out)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
6. The else block runs only if the loop was not ended by break:
target = 7
for x in [2, 4, 6, 8]:
if x == target:
print("found")
break
else:
print("not found")
not found
7.
for i in range(1, 5):
print("#" * i)
#
##
###
####
Model answers (5 and 10 marks)
Q1. Explain the if, if-else, if-elif-else and match statements of Python with examples. (5 marks)
A conditional statement runs a block only when a condition is true. A block is marked by indentation after a colon.
ifruns the block when the condition is true and does nothing otherwise.if-elsechooses between two blocks.if-elif-elsechooses one block out of many. Tests are made from the top and the first true one is taken (Plate 2.1b), so the order matters.- Conditional expression:
result = "Pass" if marks >= 40 else "Fail"for a two-way value. match(Python 3.10 and later) compares one value against patterns such ascase 1:,case "Sat" | "Sun":andcase _:(the default). It is neat for menu choices and for splitting a tuple.
def grade(marks):
if marks >= 80:
return "Distinction"
elif marks >= 60:
return "First division"
elif marks >= 40:
return "Pass"
else:
return "Fail"
def day_type(day):
match day:
case "Sat":
return "holiday"
case "Sun" | "Mon":
return "working (Nepal week starts on Sunday)"
case _:
return "working"
print([grade(m) for m in (85, 60, 59, 40, 39)])
print(day_type("Sat"), "|", day_type("Sun"), "|", day_type("Wed"))
['Distinction', 'First division', 'Pass', 'Pass', 'Fail']
holiday | working (Nepal week starts on Sunday) | working
Boundary marks 60 and 40 are tested on purpose, because >= includes the boundary. Conditions can be joined with and, or and not, and a chain such as 0 <= m <= 100 is allowed.
Q2. Explain break, continue, pass and the else clause of a loop with a program. (5 marks)
These four statements change the normal path of a loop (Fig. 2.2).
breakends the innermost loop at once; control goes to the first statement after the loop.continueabandons the rest of the current pass and goes back to the loop test (for aforloop, to the next item).passdoes nothing; it is a placeholder where Python needs a block, such asclass Empty: pass.elseon a loop runs only when the loop ends withoutbreak. For a search it means "not found".
The program lists the primes below 30 by trial division. continue skips the even numbers, break stops testing as soon as a divisor is found, and else records a prime.
primes = []
for n in range(2, 30):
if n > 2 and n % 2 == 0:
continue
for d in range(3, int(n ** 0.5) + 1, 2):
if n % d == 0:
break
else:
primes.append(n)
print(primes, len(primes))
for _ in range(2):
pass
print("done")
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29] 10
done
Because the loop only tries odd divisors up to the square root of n, a number such as 29 needs just 2 tests (3 and 5), not 27.
Q3. Explain the while and for loops of Python with range. Write programs for a multiplication table, a star pattern and the digit sum of a number, and compare the two loops. (10 marks)
Introduction. A loop repeats a block while a condition holds or for every item of a sequence. Python has two loops: while, which repeats on a condition, and for, which walks over an iterable. Both can be nested, and both accept break, continue and else.
The while loop. Syntax: while condition: followed by an indented body. The condition is tested before every pass, so the body may run zero times.
The body must change something so that the condition becomes false, otherwise the loop never ends (Fig. 2.1 shows a while loop of 111 passes whose length nobody can guess).
The for loop and range. for item in sequence: takes each item in turn from a list, string, tuple, dictionary or range. range(stop), range(start, stop) and range(start, stop, step) produce integers up to, but not including, stop.
So range(1, 11) gives 1 to 10 and range(10, 0, -3) gives 10, 7, 4, 1. A range stores only its three numbers, not the whole list, so it uses very little memory.
Programs.
n = 7
for i in range(1, 6):
print(f"{n} x {i} = {n * i}")
for row in range(1, 5):
print(" " * (4 - row) + "*" * (2 * row - 1))
num, total = 98765, 0
while num > 0:
total += num % 10
num //= 10
print("digit sum =", total)
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
*
***
*****
*******
digit sum = 35
Nested loops. In the star pattern, the outer loop picks the row and the inner work (string repetition) draws its stars; a nested for inside a for runs the inner body rows x columns times, so 4 rows of 3 columns give 12 passes.
Comparison.
| Point | while |
for |
|---|---|---|
| Repeats | while a condition is true | once for each item |
| Count known in advance | not needed | yes (the sequence is fixed) |
| Loop variable | updated by you | assigned by Python |
| Risk of an infinite loop | high | very low |
| Typical use | input validation, convergence | lists, ranges, files |
else clause |
runs when condition becomes false | runs when items are exhausted |
Common mistakes: forgetting the update in a while loop, expecting range(5) to include 5, and changing a list while looping over it.
Conclusion. Choose for when the items are known and while when only the stopping condition is known; use break, continue and else to steer the path, and keep nesting shallow.