TechLead
Lesson 3 of 25
5 min read
Python

Control Flow

Master if/elif/else, for and while loops, match statements, and control flow best practices

Conditional Statements

Python uses if, elif, and else for conditional branching. Unlike many languages, Python does not have a switch/case statement in older versions, but Python 3.10 introduced structural pattern matching with match/case.

# Basic if/elif/else
temperature = 35

if temperature > 30:
    print("It's hot outside!")
elif temperature > 20:
    print("Nice weather!")
elif temperature > 10:
    print("A bit chilly")
else:
    print("It's cold!")

# Conditional expressions (ternary operator)
age = 20
status = "adult" if age >= 18 else "minor"
print(status)  # "adult"

# Chained comparisons (Pythonic!)
x = 15
if 10 < x < 20:
    print("x is between 10 and 20")

# Multiple conditions
score = 85
has_bonus = True

if score >= 80 and has_bonus:
    print("You passed with distinction!")

# Truthy/falsy in conditions
items = [1, 2, 3]
if items:  # Non-empty list is truthy
    print(f"List has {len(items)} items")

name = ""
if not name:  # Empty string is falsy
    print("Name is empty")

For Loops

Python's for loop iterates over any iterable object — lists, strings, tuples, dictionaries, ranges, files, and more. It is fundamentally different from C-style for loops; think of it as a "for each" loop.

# Iterating over a list
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)

# range() for numeric iteration
for i in range(5):         # 0, 1, 2, 3, 4
    print(i)

for i in range(2, 10, 3):  # 2, 5, 8 (start, stop, step)
    print(i)

# enumerate() - get index and value
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")

# Iterating over a dictionary
scores = {"Alice": 95, "Bob": 87, "Charlie": 92}
for name, score in scores.items():
    print(f"{name}: {score}")

for key in scores:           # iterates over keys by default
    print(key)

for value in scores.values():  # iterate over values
    print(value)

# zip() - iterate over multiple iterables in parallel
names = ["Alice", "Bob", "Charlie"]
ages = [30, 25, 35]
for name, age in zip(names, ages):
    print(f"{name} is {age}")

# Nested loops
for i in range(3):
    for j in range(3):
        print(f"({i}, {j})", end=" ")
    print()

While Loops

The while loop repeats as long as a condition is true. Use it when you do not know in advance how many iterations you need. Always ensure there is a way for the condition to become false, otherwise you create an infinite loop.

# Basic while loop
count = 0
while count < 5:
    print(count)
    count += 1

# While with user input
# while True:
#     user_input = input("Enter 'quit' to exit: ")
#     if user_input == "quit":
#         break
#     print(f"You entered: {user_input}")

# While with else (executes if loop completes without break)
n = 10
while n > 0:
    n -= 1
    if n == 5:
        continue  # skip 5
    print(n)
else:
    print("Loop completed normally")

# Practical example: binary search
def binary_search(arr, target):
    low, high = 0, len(arr) - 1
    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1
    return -1

sorted_list = [1, 3, 5, 7, 9, 11, 13]
print(binary_search(sorted_list, 7))  # 3

Break, Continue, and Else

break exits the current loop entirely. continue skips the rest of the current iteration and moves to the next one. Python uniquely supports an else clause on loops, which executes only if the loop completes without hitting a break.

# break - exit the loop
for n in range(100):
    if n > 5:
        break
    print(n)  # 0, 1, 2, 3, 4, 5

# continue - skip current iteration
for n in range(10):
    if n % 2 == 0:
        continue
    print(n)  # 1, 3, 5, 7, 9

# for/else - else runs only if no break occurred
def find_prime_factor(n):
    for i in range(2, n):
        if n % i == 0:
            print(f"First factor of {n} is {i}")
            break
    else:
        print(f"{n} is prime!")

find_prime_factor(17)  # "17 is prime!"
find_prime_factor(15)  # "First factor of 15 is 3"

Structural Pattern Matching (Python 3.10+)

Python 3.10 introduced match/case statements, which are far more powerful than simple switch/case. They support destructuring, guards, type matching, and complex patterns.

# Basic pattern matching
def handle_command(command):
    match command.split():
        case ["quit"]:
            print("Quitting...")
        case ["go", direction]:
            print(f"Going {direction}")
        case ["get", item] if item != "sword":
            print(f"Picking up {item}")
        case ["get", "sword"]:
            print("The sword is too heavy!")
        case _:
            print(f"Unknown command: {command}")

handle_command("go north")    # Going north
handle_command("get shield")  # Picking up shield
handle_command("get sword")   # The sword is too heavy!

# Pattern matching with types
def process_value(value):
    match value:
        case int(n) if n > 0:
            print(f"Positive integer: {n}")
        case int(n):
            print(f"Non-positive integer: {n}")
        case str(s):
            print(f"String: {s}")
        case [x, y]:
            print(f"Two-element list: {x}, {y}")
        case {"name": name, "age": age}:
            print(f"Person: {name}, age {age}")
        case _:
            print("Something else")

process_value(42)                          # Positive integer: 42
process_value("hello")                     # String: hello
process_value([1, 2])                      # Two-element list: 1, 2
process_value({"name": "Alice", "age": 30})  # Person: Alice, age 30

Key Takeaways

  • Chained comparisons: Use 10 < x < 20 instead of x > 10 and x < 20
  • for/else: The else block runs when the loop exits without break
  • Prefer for over while: Use for loops when iterating over sequences
  • Pattern matching: Use match/case for complex conditional logic in Python 3.10+

Continue Learning