0.3 — Control Flow and List Comprehensions

Chapter 0 · Basics of Python

Prof. Xuhu Wan

Section 0.3 · Chapter 0 · Learning Statistics with Python

Control Flow and List Comprehensions

Basics of Python

Prof. Xuhu Wan

ISOM, HKUST Business School · 2026 Edition

Control Flow and List Comprehensions

Programs branch and repeat. You will predict how elif order changes a grade, why range(1, 5) has four numbers, what continue skips — and then compress a four-line loop into one line that reads like set-builder notation.

if / elif / else

With score = 59, which branch fires?

if score >= 90:   grade = "A"
elif score >= 80: grade = "B"
elif score >= 60: grade = "C"
else:             grade = "D or below"

D or below

59 D or below. Indentation is the block — four spaces, no braces. Python stops at the first branch that is True.

Order of branches matters

score = 95. if score >= 60: grade = “C” then elif score >= 90: grade = “A”. What is grade?

  • "C" — the first true branch wins
  • "A" — the best matching branch wins
  • Both run; grade ends as "A"
  • A SyntaxError — thresholds must be increasing

for loops and enumerate

Indices start at 0. enumerate(cities, 1) starts the counter at 1 — useful for printing ranks. You never write for i in range(len(cities)) in idiomatic Python.

How many numbers in range(1, 5)?

What does list(range(1, 5)) return?

  • [1, 2, 3, 4, 5]
  • [1, 2, 3, 4]
  • [0, 1, 2, 3, 4]
  • [1, 5]

while: repeat until a condition fails

n = 5; total = 0 and while n > 0: total += n; n -= 1. What is total?

print(total)

15

Warning

Forget n = n - 1 and the loop never ends. Use while only when you do not know the number of iterations in advance (e.g. “keep bidding until the order fills”); otherwise use for.

break stops; continue skips

for x in range(1, 11): if x % 3 == 0: continue; print(x, end=” “). Output?

  • 1 2
  • 3 6 9
  • 1 2 4 5 7 8 10
  • 1 2 3 4 5 6 7 8 9 10

Run both

First multiple of 7: 7 and 1 2 4 5 7 8 10. break is how a search loop exits early; continue is how a cleaning loop discards bad rows without nesting the whole body in an if.

Your turn: FizzBuzz

Fill the list fizz for 1..20: multiples of 3 become "Fizz", multiples of 5 "Buzz", multiples of both "FizzBuzz", everything else the number as a string. Test the “both” case first.

List comprehensions

[new_item for item in iterable if condition] — a loop that builds a list in one expression. Predict what each variant produces before you run it.

The loop and its one-line twin

What does [x**2 for x in range(0, 6)] return?

squares = [x**2 for x in range(0, 6)]
print(squares)

[0, 1, 4, 9, 16, 25]

Add a filter

What does [x**2 for x in range(10) if x % 2 == 0] return?

  • [0, 4, 16, 36, 64]
  • [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  • [1, 9, 25, 49, 81]
  • [0, 4, 16, 36, 64, 100]

if after for filters; if … else before for labels

How many elements does [“even” if x % 2 == 0 else “odd” for x in range(6)] have?

  • 3
  • 0
  • 6 — every element gets a label
  • It is a SyntaxError

['even', 'odd', 'even', 'odd', 'even', 'odd'] and ['NYC', 'LA', 'CHICAGO']. The label pattern becomes np.where(cond, "even", "odd") in Chapter 1 — same idea, vectorised.

Your turn: filter, then map

Mirror the even_squares example: build odd_cubes, the cubes of the odd numbers in range(10), as one comprehension. Expected: [1, 27, 125, 343, 729].

What you discovered

  • Python takes the first true branch — order if/elif from strictest to loosest.
  • range(1, 5) is 1, 2, 3, 4: the same stop-exclusive rule as slicing.
  • enumerate gives (index, value); for i in range(len(x)) is a smell.
  • break exits the loop; continue skips to the next iteration; while needs a guaranteed exit.
  • [f(x) for x in xs if cond] filters then maps; [a if c else b for x in xs] labels every element.

Next: §0.4 — wrap the logic in functions, format the output, and survive bad input.