Control Structures
Introduction
Programs rarely execute linearly from top to bottom. Control structures allow you to make decisions, repeat actions, and change the flow of execution based on conditions.
Learning Objectives
By the end of this reading, you will be able to:
- Write conditional statements (if/else)
- Use different types of loops (for, while)
- Control loop execution with break and continue
- Nest control structures appropriately
- Choose the right control structure for a problem
1. Sequential Execution
By default, code executes line by line:
print("First")
print("Second")
print("Third")
# Output: First, Second, Third
Control structures change this flow.
2. Conditional Statements
Basic If Statement
Execute code only if a condition is true:
age = 20
if age >= 18:
print("You are an adult")
Key points:
- Condition must evaluate to a boolean (or be "truthy"/"falsy")
- Indentation defines the code block
- Colon
:after the condition
If-Else
Handle both true and false cases:
temperature = 35
if temperature > 30:
print("It's hot!")
else:
print("It's not too hot")
If-Elif-Else
Multiple conditions:
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else:
grade = "F"
print(f"Your grade: {grade}") # B
Important: Only the first matching condition executes.
x = 15
if x > 5:
print("Greater than 5") # This prints
elif x > 10:
print("Greater than 10") # This doesn't (even though true)
Conditional Expressions (Ternary)
One-line conditionals:
age = 20
status = "adult" if age >= 18 else "minor"
print(status) # "adult"
# Equivalent to:
if age >= 18:
status = "adult"
else:
status = "minor"
Truthiness
Python evaluates these as False:
FalseNone0(zero of any numeric type)""(empty string)[](empty list){}(empty dict)set()(empty set)
Everything else is True:
name = ""
if name:
print(f"Hello, {name}")
else:
print("No name provided") # This runs
items = [1, 2, 3]
if items:
print("List has items") # This runs
3. Comparison and Logical Operators
Comparison Operators
x = 5
y = 10
x == y # Equal: False
x != y # Not equal: True
x < y # Less than: True
x > y # Greater than: False
x <= y # Less than or equal: True
x >= y # Greater than or equal: False
Logical Operators
a = True
b = False
a and b # False (both must be true)
a or b # True (at least one true)
not a # False (inverts)
# Combining conditions
age = 25
income = 50000
if age >= 18 and income >= 30000:
print("Eligible for loan")
# Chained comparisons
x = 5
if 0 < x < 10: # Same as: 0 < x and x < 10
print("x is between 0 and 10")
Short-Circuit Evaluation
Python stops evaluating as soon as the result is determined:
# 'and' stops at first False
False and expensive_function() # expensive_function never called
# 'or' stops at first True
True or expensive_function() # expensive_function never called
# Practical use:
if user and user.is_active: # Avoids error if user is None
process(user)
4. Loops
For Loops
Iterate over a sequence:
# Iterate over a list
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
# Iterate over a string
for char in "Hello":
print(char)
# Iterate over a range
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(2, 6): # 2, 3, 4, 5
print(i)
for i in range(0, 10, 2): # 0, 2, 4, 6, 8 (step of 2)
print(i)
While Loops
Repeat while a condition is true:
count = 0
while count < 5:
print(count)
count += 1
# Output: 0, 1, 2, 3, 4
# Waiting for input
password = ""
while password != "secret":
password = input("Enter password: ")
print("Access granted!")
Danger: Infinite loops
# This runs forever!
while True:
print("Forever...")
# Common mistake - forgetting to update condition
x = 0
while x < 5:
print(x)
# Forgot: x += 1
Loop Control
break: Exit the loop immediately
for i in range(10):
if i == 5:
break
print(i)
# Output: 0, 1, 2, 3, 4
continue: Skip to next iteration
for i in range(5):
if i == 2:
continue
print(i)
# Output: 0, 1, 3, 4 (skips 2)
else on loops: Runs if loop completes without break
for i in range(5):
if i == 10: # Never true
break
else:
print("Loop completed normally") # This prints
for i in range(5):
if i == 3:
break
else:
print("Loop completed normally") # This doesn't print
Nested Loops
# Multiplication table
for i in range(1, 4):
for j in range(1, 4):
print(f"{i} × {j} = {i*j}")
print("---")
# Output:
# 1 × 1 = 1
# 1 × 2 = 2
# 1 × 3 = 3
# ---
# 2 × 1 = 2
# ... etc
5. Iterating with Indices
enumerate()
Get both index and value:
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry
# Start from different index
for index, fruit in enumerate(fruits, start=1):
print(f"{index}: {fruit}")
# 1: apple
# 2: banana
# 3: cherry
zip()
Iterate over multiple sequences:
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
for name, age in zip(names, ages):
print(f"{name} is {age}")
# Alice is 25
# Bob is 30
# Charlie is 35
Iterating Dictionaries
person = {"name": "Alice", "age": 25, "city": "Boston"}
# Keys
for key in person:
print(key)
# Values
for value in person.values():
print(value)
# Both
for key, value in person.items():
print(f"{key}: {value}")
6. List Comprehensions
Concise way to create lists:
# Traditional loop
squares = []
for x in range(5):
squares.append(x ** 2)
# List comprehension
squares = [x ** 2 for x in range(5)]
# [0, 1, 4, 9, 16]
# With condition
evens = [x for x in range(10) if x % 2 == 0]
# [0, 2, 4, 6, 8]
# With transformation
words = ["hello", "world"]
upper = [w.upper() for w in words]
# ["HELLO", "WORLD"]
Other Comprehensions
# Set comprehension
unique_lengths = {len(word) for word in ["hi", "hello", "hey"]}
# {2, 5, 3}
# Dictionary comprehension
squares_dict = {x: x**2 for x in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# Generator expression (memory-efficient)
sum_of_squares = sum(x**2 for x in range(1000000))
7. Match Statement (Python 3.10+)
Pattern matching for complex conditions:
def handle_command(command):
match command.split():
case ["quit"]:
return "Goodbye!"
case ["load", filename]:
return f"Loading {filename}"
case ["save", filename]:
return f"Saving {filename}"
case ["move", x, y]:
return f"Moving to ({x}, {y})"
case _:
return "Unknown command"
print(handle_command("load data.txt")) # Loading data.txt
print(handle_command("move 10 20")) # Moving to (10, 20)
Matching with Guards
def categorize_number(n):
match n:
case 0:
return "zero"
case n if n < 0:
return "negative"
case n if n % 2 == 0:
return "positive even"
case _:
return "positive odd"
8. Common Patterns
Finding an Item
def find_first_negative(numbers):
for num in numbers:
if num < 0:
return num
return None
result = find_first_negative([1, 2, -3, 4])
print(result) # -3
Counting
def count_vowels(text):
count = 0
for char in text.lower():
if char in "aeiou":
count += 1
return count
# Or with sum and comprehension
def count_vowels(text):
return sum(1 for char in text.lower() if char in "aeiou")
Accumulating
def total_price(items):
total = 0
for item in items:
total += item["price"]
return total
# Or with sum
def total_price(items):
return sum(item["price"] for item in items)
Filtering
def get_adults(people):
adults = []
for person in people:
if person["age"] >= 18:
adults.append(person)
return adults
# Or with comprehension
def get_adults(people):
return [p for p in people if p["age"] >= 18]
# Or with filter
def get_adults(people):
return list(filter(lambda p: p["age"] >= 18, people))
Transforming
def double_all(numbers):
result = []
for n in numbers:
result.append(n * 2)
return result
# Or with comprehension
def double_all(numbers):
return [n * 2 for n in numbers]
# Or with map
def double_all(numbers):
return list(map(lambda n: n * 2, numbers))
9. Best Practices
Avoid Deep Nesting
# Hard to read
if condition1:
if condition2:
if condition3:
do_something()
# Better - guard clauses
if not condition1:
return
if not condition2:
return
if not condition3:
return
do_something()
Prefer For Over While When Possible
# Unclear when it ends
i = 0
while i < len(items):
process(items[i])
i += 1
# Clear and concise
for item in items:
process(item)
Use Meaningful Loop Variables
# Unclear
for x in data:
print(x)
# Clear
for user in users:
print(user)
for row_index, row in enumerate(matrix):
for col_index, value in enumerate(row):
print(f"[{row_index}][{col_index}] = {value}")
Exercises
Basic
Write a program that prints "Fizz" for multiples of 3, "Buzz" for multiples of 5, and "FizzBuzz" for multiples of both, for numbers 1-20.
Given a list of numbers, print only the positive ones:
numbers = [1, -2, 3, -4, 5, -6]
- Use a while loop to find the first power of 2 greater than 1000.
Intermediate
Write a program that finds all prime numbers between 2 and 50.
Create a number guessing game:
- Computer picks a random number 1-100
- User guesses until correct
- Give "higher" or "lower" hints
import random
target = random.randint(1, 100)
# Your code here
- Given a list of words, create a dictionary mapping each word to its length:
words = ["apple", "banana", "cherry", "date"]
# Expected: {"apple": 5, "banana": 6, "cherry": 6, "date": 4}
Advanced
Write a program that prints a multiplication table (1-10) formatted nicely.
Implement a simple calculator that:
- Continuously prompts for expressions like "5 + 3"
- Supports +, -, *, /
- Quits when user types "quit"
Using nested loops, print this pattern:
*
**
***
****
*****
****
***
**
*
Summary
- Conditionals (if/elif/else) make decisions
- For loops iterate over sequences
- While loops repeat until a condition is false
- break exits loops; continue skips iterations
- List comprehensions provide concise list creation
- Match statements (3.10+) handle complex pattern matching
- Choose the right structure: for when you know iterations, while when you don't