Skip to content

Control Flow

Control flow decides which line of code runs and when. It helps your program:

  • make decisions based on conditions
  • repeat tasks efficiently
  • stop or skip steps when needed
  • handle different scenarios dynamically

These statements are used to make decisions and control program flow.

  • if → checks a condition (executes if True)
  • elif → checks another condition if the first is false
  • else → runs if all conditions are false

Order matters: elif and else blocks are optional, and multiple elif blocks can be chained.

x = 10
if x > 10:
print("Greater than 10")
elif x == 10:
print("Equal to 10")
else:
print("Less than 10")

Professional Pattern: Use elif for multiple conditions instead of nested if statements for better readability.

graph TD Start -->|Input| x["x = ?"] x --> C1{"x > 10"} C1 -->|True| A["✓ Greater than 10"] C1 -->|False| C2{"x == 10"} C2 -->|True| B["✓ Equal to 10"] C2 -->|False| C["✓ Less than 10"]

A concise way to write simple if-else statements in a single line. Also called conditional expression.

age = 18
status = "Adult" if age >= 18 else "Minor"
print(status) # Output: Adult

Syntax: value_if_true if condition else value_if_false

Use Cases:

  • Simple assignments based on conditions
  • Default values
  • Avoiding verbose if-else blocks

Gotcha: Avoid nesting multiple ternary operators as it reduces readability.

graph TD A["condition"] -->|True| B["value_if_true"] A -->|False| C["value_if_false"]

Uses pattern matching to compare one value against multiple patterns. Available in Python 3.10+.

def check(value):
match value:
case 1:
return "One"
case 2:
return "Two"
case _:
return "Other"
print(check(2)) # Output: Two

Key Features:

  • case pattern: → matches a specific value
  • _ → default case (matches anything)
  • More readable than many if-elif-else chains
  • Better performance for many conditions

Advanced Patterns:

match point:
case (0, 0):
print("Origin")
case (0, y):
print(f"On Y axis: {y}")
case (x, 0):
print(f"On X axis: {x}")
case _:
print("General point")
graph TD Start[( value )] -->|case 1| One["→ One"] Start -->|case 2| Two["→ Two"] Start -->|default _| Default["→ Other"]

A for loop iterates through items in a sequence one by one. It’s the most common loop type in Python.

for i in range(3):
print(i)

Output:

0
1
2

Iteration Over Collections:

names = ["A", "B", "C"]
for name in names:
print(name)

Professional Tips:

  • Use for loops instead of while when iterating over sequences
  • Use enumerate() when you need both index and value
  • Use zip() to iterate over multiple sequences simultaneously
  • Prefer descriptive variable names: for user in users: instead of for u in users:
graph TD Start --> Init["i ∈ [0,1,2]"] Init --> i0["i=0"] i0 --> Print0["↓ print"] Print0 --> i1["i=1"] i1 --> Print1["↓ print"] Print1 --> i2["i=2"] i2 --> Print2["↓ print"] Print2 --> End["✓ Done"]

A while loop runs repeatedly until the condition becomes false.

count = 0
while count < 3:
print(count)
count += 1

Key Difference from for loops:

  • for → iterate over known sequences
  • while → loop until a condition is met
  • Risk of infinite loops if condition never becomes false

Common Patterns:

# Input validation
while True:
user_input = input("Enter a number: ")
if user_input.isdigit():
break
# Event loop simulation
running = True
while running:
handle_events()
update()
render()
graph TD Start --> Condition{"count < 3"} Condition -->|✓ Yes| Print["print & increment"] Print -->|Loop| Condition Condition -->|✗ No| End["✓ Exit"]

These control statements fine-tune loop behavior for complex scenarios.

Stops the loop immediately and exits completely.

for i in range(5):
if i == 3:
break # Exits loop when i equals 3
print(i)

Output: 0 1 2

Skips the current iteration and jumps to the next one.

for i in range(5):
if i == 2:
continue # Skips i=2
print(i)

Output: 0 1 3 4

A null operation — does nothing when executed. Useful as a placeholder.

for i in range(5):
if i == 2:
pass # Placeholder, does nothing
if i == 3:
pass # Also valid
print(i)

Executes only if the loop completes normally without hitting break.

for i in range(3):
print(i)
else:
print("Loop finished normally")
# Search example
for user in users:
if user.id == target_id:
print("User found")
break
else:
print("User not found")
graph TD Start["Start: for i in range(5)"] --> LoopCheck{"Next item exists?"} LoopCheck -->|No| ElseBlock["Run else block"] ElseBlock --> End["End"] LoopCheck -->|Yes| Body["Execute Loop Body"] Body --> Condition{"i == 3?"} Condition -->|Yes| Break["break -> Exit Loop"] Break --> EndBreak["End (else NOT executed)"] Condition -->|No| Continue["Continue Loop"] Continue --> LoopCheck

range() generates a sequence of numbers efficiently. It’s commonly used in loops.

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

Three Forms:

  1. range(end) → from 0 to end-1

    range(5) # 0, 1, 2, 3, 4
  2. range(start, end) → from start to end-1

    range(1, 6) # 1, 2, 3, 4, 5
  3. range(start, end, step) → from start to end-1, incrementing by step

    range(0, 10, 2) # 0, 2, 4, 6, 8
    range(10, 0, -2) # 10, 8, 6, 4, 2 (reverse)

Professional Knowledge:

  • range() returns a range object (lazy evaluation, memory efficient)
  • Convert to list if needed: list(range(5))
  • Can be used with negative steps for iteration in reverse

Adds an index (position) to each item when iterating. Essential for loops where you need both position and value.

items = ["a", "b", "c"]
for index, value in enumerate(items):
print(index, value)

Output:

0 a
1 b
2 c

Customizing Start Index:

for index, value in enumerate(items, start=1):
print(index, value)

Output:

1 a
2 b
3 c

Real-World Example:

tasks = ["buy milk", "pay bills", "exercise"]
for num, task in enumerate(tasks, 1):
print(f"{num}. {task}")
# Output:
# 1. buy milk
# 2. pay bills
# 3. exercise
graph TD A["['a','b','c']"] --> B["enumerate()"] B --> C["(0, 'a')"] B --> D["(1, 'b')"] B --> E["(2, 'c')"]

Combines multiple sequences together element-by-element. Perfect for parallel iteration.

names = ["A", "B"]
scores = [90, 80]
for name, score in zip(names, scores):
print(name, score)

Output:

A 90
B 80

Key Behaviors:

  • Stops when shortest sequence ends
  • Works with any iterable (lists, tuples, strings, etc.)
names = ["A", "B", "C"]
scores = [90, 80] # Only 2 elements
for name, score in zip(names, scores):
print(name, score)
# Output:
# A 90
# B 80
# C is skipped because no corresponding score

Practical Examples:

# Merge multiple lists
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
combined = list(zip(list1, list2))
# Output: [(1, 'a'), (2, 'b'), (3, 'c')]
# Process related data in parallel
students = ["Alice", "Bob", "Charlie"]
gpa = [3.8, 3.5, 3.9]
for student, grade in zip(students, gpa):
print(f"{student}: {grade}")
graph TD A["names: ['A','B']"] --> Z["zip()"] B["scores: [90,80]"] --> Z Z --> P1["('A', 90)"] Z --> P2["('B', 80)"]