Control Flow
Conditionals, loops, and branching logic.
Conditionals
if / elif / else
age = 25
if age < 18:
print("Minor")
elif age < 65:
print("Adult")
else:
print("Senior")
Comparison Operators
| Operator | Meaning |
|---|---|
== | Equal |
!= | Not equal |
< | Less than |
> | Greater than |
<= | Less than or equal |
>= | Greater than or equal |
is | Same object |
is not | Different object |
in | Membership |
not in | Non-membership |
Combining Conditions
# and - both must be true
if age >= 18 and age < 65:
print("Working age")
# or - either can be true
if day == "Saturday" or day == "Sunday":
print("Weekend")
# not - negation
if not is_logged_in:
print("Please log in")
# Chained comparisons
if 18 <= age < 65: # Same as: age >= 18 and age < 65
print("Working age")
if a == b == c: # All equal
print("All same")
Ternary Expression
# condition_true if condition else condition_false
status = "adult" if age >= 18 else "minor"
# Can be nested (but avoid deep nesting)
size = "large" if x > 100 else "medium" if x > 50 else "small"
Truthiness in Conditionals
# These are all equivalent
if items: # Pythonic
if len(items) > 0: # Explicit but verbose
if items != []: # Avoid
# Check for None specifically
if x is None: # Correct
if x == None: # Works but not idiomatic
if not x: # Wrong - also catches 0, "", [], etc.
Match Statement (3.10+)
Pattern matching - more powerful than switch/case:
Basic Matching
def http_status(code):
match code:
case 200:
return "OK"
case 404:
return "Not Found"
case 500:
return "Server Error"
case _: # Wildcard (default)
return "Unknown"
Pattern Matching
# Match multiple values
match code:
case 200 | 201 | 204:
return "Success"
case 400 | 401 | 403 | 404:
return "Client Error"
# Match with guards
match point:
case (x, y) if x == y:
print("On diagonal")
case (x, y):
print(f"Point at {x}, {y}")
# Match structure
match data:
case {"type": "user", "name": name}:
print(f"User: {name}")
case {"type": "error", "message": msg}:
print(f"Error: {msg}")
case [first, *rest]:
print(f"List starting with {first}")
# Match class instances
match event:
case Click(x, y):
handle_click(x, y)
case KeyPress(key):
handle_key(key)
Loops
for Loop
Iterates over any iterable:
# List
for item in [1, 2, 3]:
print(item)
# String
for char in "hello":
print(char)
# Range
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(2, 8): # 2, 3, 4, 5, 6, 7
print(i)
for i in range(0, 10, 2): # 0, 2, 4, 6, 8
print(i)
for i in range(10, 0, -1): # 10, 9, 8, ... 1
print(i)
# Dictionary
for key in my_dict:
print(key)
for key, value in my_dict.items():
print(f"{key}: {value}")
# With index
for i, item in enumerate(items):
print(f"{i}: {item}")
for i, item in enumerate(items, start=1): # Start from 1
print(f"{i}: {item}")
# Multiple iterables
for a, b in zip(list1, list2):
print(f"{a} - {b}")
while Loop
count = 0
while count < 5:
print(count)
count += 1
# With condition
while True:
line = input()
if line == "quit":
break
print(line)
Loop Control
# break - exit loop entirely
for i in range(10):
if i == 5:
break
print(i) # 0, 1, 2, 3, 4
# continue - skip to next iteration
for i in range(5):
if i == 2:
continue
print(i) # 0, 1, 3, 4
# else - runs if loop completes without break
for item in items:
if item == target:
print("Found!")
break
else:
print("Not found") # Only runs if no break
Nested Loops
for i in range(3):
for j in range(3):
print(f"({i}, {j})")
# Breaking out of nested loops
found = False
for i in range(10):
for j in range(10):
if condition:
found = True
break
if found:
break
# Cleaner with a function
def find_match():
for i in range(10):
for j in range(10):
if condition:
return (i, j)
return None
Iterables and Iterators
Common Iterables
# Sequences
list, tuple, str, range, bytes
# Collections
dict, set, frozenset
# Files
for line in open("file.txt"):
print(line)
# Generators
(x**2 for x in range(10))
Useful Iteration Functions
# enumerate - index + value
for i, val in enumerate(['a', 'b', 'c']):
print(i, val) # 0 a, 1 b, 2 c
# zip - parallel iteration
for a, b in zip([1, 2, 3], ['a', 'b', 'c']):
print(a, b) # 1 a, 2 b, 3 c
# reversed - iterate backwards
for x in reversed([1, 2, 3]):
print(x) # 3, 2, 1
# sorted - iterate in order
for x in sorted([3, 1, 2]):
print(x) # 1, 2, 3
# filter - only matching items
for x in filter(lambda n: n > 0, [-1, 0, 1, 2]):
print(x) # 1, 2
# map - transform each item
for x in map(str.upper, ['a', 'b', 'c']):
print(x) # A, B, C
Unpacking in Loops
# Tuple unpacking
points = [(1, 2), (3, 4), (5, 6)]
for x, y in points:
print(f"x={x}, y={y}")
# Dict items
for key, value in my_dict.items():
print(f"{key}: {value}")
# Star unpacking
data = [(1, 2, 3, 4), (5, 6, 7, 8)]
for first, *middle, last in data:
print(first, middle, last) # 1 [2, 3] 4
Common Patterns
Early Return / Guard Clauses
# Instead of nested ifs
def process(data):
if data is None:
return None
if not data:
return []
if not is_valid(data):
raise ValueError("Invalid data")
# Main logic here (not nested)
return transform(data)
Loop with Else
# Search pattern
def find_item(items, target):
for item in items:
if item == target:
return item
else:
return None # Not found
# Prime check
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return False
return True
Infinite Loop with Break
# Menu pattern
while True:
choice = input("Enter choice (q to quit): ")
if choice == 'q':
break
process_choice(choice)
Flag Variables
# Track state across iterations
found = False
for item in items:
if matches(item):
found = True
break
if found:
print("Found a match")
Practice
# 1. FizzBuzz
for i in range(1, 101):
if i % 15 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
# 2. Find first match
def first_even(numbers):
for n in numbers:
if n % 2 == 0:
return n
return None
# 3. Count occurrences
text = "hello world"
counts = {}
for char in text:
counts[char] = counts.get(char, 0) + 1
# 4. Nested loop - multiplication table
for i in range(1, 11):
for j in range(1, 11):
print(f"{i*j:4}", end="")
print()