Python: Control Flow

Master every tool Python gives you to make decisions and repeat actions: if statements, loops, match-case, and loop control keywords.

if Statement

The if statement is the most fundamental decision-making tool in Python. It evaluates a condition and runs the indented block beneath it only when that condition is True. The condition can be any expression that produces a boolean, including comparisons, membership tests, function calls, or even a plain variable (Python treats non-zero numbers, non-empty strings, and non-empty collections as truthy).

Truthy and Falsy Values

Python evaluates any value as a boolean when used in an if condition.

  • Falsy: 0, 0.0, "", [], {}, (), None, False
  • Truthy: any non-zero number, non-empty string, non-empty collection, True
  • if x: is shorthand for if x is truthy, avoiding an explicit comparison
  • The condition does not need parentheses (though they are allowed)

Basic if Statement

Python

The block runs only when the condition evaluates to True.

if-else Statement

Adding an else clause gives you two branches: one that runs when the condition is True, and one that runs when it is False. Exactly one of the two blocks will always execute, never both and never neither.

if-else Statement

Python

Always one branch executes, never both.

elif Ladder

When you have more than two possible outcomes, chain additional conditions with elif (short for "else if"). Python checks each condition from top to bottom and executes only the first block whose condition is True, then skips the rest of the chain entirely. A closing else handles every case not covered above.

elif Best Practices

The elif chain short-circuits: once one condition matches, nothing else is checked.

  • Put the most specific or most likely condition first for efficiency
  • You can have as many elif clauses as you need
  • The final else is optional but acts as a safety net for unexpected values
  • Avoid deeply nested if-elif; consider a dictionary dispatch or match-case instead

elif Ladder - Grade Calculator

Python

Only the first matching branch executes; the rest are skipped.

Nested if-else

You can place an if statement inside another if block to check a secondary condition only after the first has passed. This is called nesting. While sometimes necessary, deep nesting (more than two levels) makes code hard to follow. Flattening with elif or using early returns inside functions is usually cleaner.

Nested if-else

Python

An inner if runs only after the outer condition passes.

match-case Statement (Python 3.10+)

Python 3.10 introduced structural pattern matching via the match statement. It is similar to a switch statement in other languages but considerably more powerful because it can match against values, types, sequences, mappings, and even bind parts of the matched value to variables. The case _: wildcard acts as the default and catches anything not matched above.

match-case vs if-elif

Use match-case when dispatching on the value or structure of a single subject.

  • Cleaner than a long if-elif chain when testing one variable against many values
  • case _: is the catch-all default (equivalent to else)
  • Can match sequences: case [x, y]: binds list elements to x and y
  • Can match with guards: case x if x > 0: adds an extra condition
  • Requires Python 3.10 or newer; use if-elif for older versions

match-case Statement

Python

Matching HTTP status codes to descriptive messages.

for Loop

Python's for loop iterates over any iterable: a list, string, tuple, range, dictionary, file, or any other object that supports iteration. On each pass through the loop, the loop variable is bound to the next item in the sequence. You do not manage an index or a counter manually; Python handles all of that for you.

for Loop Syntax

for variable in iterable: is the complete syntax. No special keywords needed to advance to the next item.

  • The loop variable is created automatically and is available inside the block
  • After the loop finishes, the loop variable retains its last value
  • Use _ as the variable name when you do not need the value: for _ in range(5)
  • Works on any iterable: lists, strings, tuples, sets, dicts, generators

Basic for Loop

Python

Iterating over a list and computing a running total.

Iterating over Strings, Lists, Tuples

The for loop works identically across all sequence types. When iterating a string, Python yields one character per iteration. When iterating a tuple, it yields each element exactly as it would for a list.

Iterating Strings, Lists, Tuples

Python

The same for loop syntax handles every sequence type.

range() Function

range() generates a sequence of integers on demand without storing them all in memory. It accepts one, two, or three arguments: stop; start and stop; or start, stop, and step. The stop value is always excluded from the sequence, which is a source of off-by-one confusion for many beginners.

range() Signatures

range() is a lazy generator: it produces values one at a time, which is very memory-efficient.

  • range(stop): 0, 1, 2, ..., stop-1
  • range(start, stop): start, start+1, ..., stop-1
  • range(start, stop, step): start, start+step, ..., up to but not including stop
  • Negative step counts backwards: range(10, 0, -1)
  • Convert to a list with list(range(5)) when you need to inspect the values

range() Variations

Python

One, two, and three argument forms including a countdown.

Nested for Loops

Placing one for loop inside another creates a nested loop. The inner loop runs to completion on every single pass of the outer loop. This is the standard approach for working with 2D data structures like grids, matrices, and tables. Be mindful: if the outer loop runs N times and the inner runs M times, the total iterations are N times M.

Nested for Loops - Multiplication Table

Python

The inner loop completes fully for every single step of the outer loop.

while Loop

A while loop keeps executing its block as long as a condition remains True. Use it when you do not know in advance how many iterations you need, such as reading user input until they type a valid value, polling a sensor, or waiting for a network response. Always make sure something inside the loop will eventually make the condition False, otherwise the loop runs forever.

for vs while

Rule of thumb: use for when you can count the iterations; use while when you cannot.

  • for is best when iterating a known collection or fixed count
  • while is best when the stopping condition depends on runtime state
  • Always update the loop variable or condition inside the while body
  • You can simulate a for loop with while, but it is more verbose and error-prone

while Loop

Python

Counting down and validating user input with a while loop.

Infinite while Loop

Writing while True: creates an intentionally infinite loop. This is not a bug; it is a recognised pattern for things like game loops, server listeners, interactive menus, and any process that should keep running until an explicit exit condition is met. You always pair it with a break statement inside the body to escape.

Infinite Loop with break

Python

while True is intentional. The break inside controls when to exit.

break Statement

The break statement immediately exits the innermost enclosing loop, regardless of whether its condition is still True or there are remaining items to iterate. Execution continues with the first statement after the loop. It is commonly used when searching a collection: once you find what you are looking for, there is no point continuing.

break Statement

Python

Stop the loop the moment the target is found.

continue Statement

The continue statement skips the rest of the current iteration's body and jumps directly to the next iteration. Unlike break, the loop itself does not end; it just moves on. This is handy for filtering out values you want to ignore without wrapping the rest of the loop body in an if block.

continue Statement

Python

Skip odd numbers and only process even ones.

pass Statement

pass is a no-op: it does absolutely nothing when executed. It exists because Python requires at least one statement inside any block (if, for, while, def, class). When you want to write the structure first and fill in the logic later, use pass as a placeholder so the code is syntactically valid and runnable even while incomplete.

Common pass Use Cases

pass is a placeholder that keeps Python happy when a block must not be empty.

  • Empty function body during development: def my_func(): pass
  • Empty class definition: class MyClass: pass
  • Intentionally ignoring an exception: except ValueError: pass
  • Empty loop body when only the side effects of iteration matter

pass Statement

Python

Placeholder in a loop, a function stub, and an exception handler.

else Clause with Loops

Python has a feature that surprises many developers from other languages: both for and while loops can have an else clause. The else block runs only if the loop completed normally without hitting a break. If the loop exits via break, the else block is skipped. This is most useful in search patterns where you want to know whether the search succeeded or exhausted all possibilities.

Loop else Clause: The Mental Model

Think of it as no break happened rather than the loop is finished.

  • else runs when the loop ends naturally (iterable exhausted or condition became False)
  • else is skipped when the loop exits via break
  • Classic use case: search and report "not found" if break never triggered
  • Works identically for both for and while loops

else Clause with for and while

Python

The else block only runs when no break was hit.

Quiz - Test Your Knowledge

Eight questions covering every concept in this tutorial. Take your time and think through each one before selecting an answer.

Knowledge Check

1. What is the output of: for i in range(2, 10, 3): print(i)?

2. Which statement immediately stops a loop and exits it entirely?

3. When does the else clause of a for loop execute?

4. What does the pass statement do?

5. Which Python version introduced the match-case statement?

6. What does continue do inside a loop?

7. What is the result of range(5)?

8. Which construct is best for matching a variable against several fixed values?