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
PythonThe 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
PythonAlways 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
PythonOnly 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
PythonAn 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
PythonMatching 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
PythonIterating 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
PythonThe 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
PythonOne, 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
PythonThe 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
PythonCounting 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
Pythonwhile 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
PythonStop 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
PythonSkip 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
PythonPlaceholder 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
PythonThe 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?