Control Flow & Functions
Learn conditional statements, loops, and function definitions for program logic
Control Flow & Functions in Python
Master Python's control flow and function fundamentals with free flashcards and spaced repetition practice. This lesson covers conditional statements, loops, function definitions, parameters, return values, and scopeβessential concepts for writing efficient, reusable Python code.
Welcome to Control Flow & Functions! π»
Every program needs to make decisions and repeat tasks. Without control flow, your code would just execute line by line with no flexibility. Without functions, you'd repeat the same code over and over. Think of control flow as the decision-making brain of your program, and functions as reusable building blocks that keep your code organized and maintainable.
In this lesson, you'll learn how to:
- Control program execution with if/elif/else statements
- Repeat tasks efficiently using for and while loops
- Create reusable code with function definitions
- Pass data using parameters and arguments
- Return results and understand variable scope
Core Concepts: Control Flow π
Conditional Statements: Making Decisions
Conditional statements allow your program to choose different paths based on conditions. The basic structure uses if, elif (else if), and else.
Syntax:
if condition:
# code block executes if condition is True
elif another_condition:
# code block executes if first is False and this is True
else:
# code block executes if all above are False
Key points:
- Conditions evaluate to
TrueorFalse(Boolean values) - Indentation (4 spaces) defines code blocks
elifandelseare optional- Only ONE block executes (the first True condition)
π‘ Tip: Python uses indentation instead of braces {} like other languages. Consistent indentation is critical!
Comparison Operators
| Operator | Meaning | Example | Result |
|---|---|---|---|
== | Equal to | 5 == 5 | True |
!= | Not equal | 5 != 3 | True |
< | Less than | 3 < 5 | True |
> | Greater than | 5 > 3 | True |
<= | Less or equal | 5 <= 5 | True |
>= | Greater or equal | 6 >= 5 | True |
Logical Operators
Combine multiple conditions using logical operators:
and- Both conditions must be Trueor- At least one condition must be Truenot- Inverts the Boolean value
age = 25
has_license = True
if age >= 18 and has_license:
print("Can drive")
π§ Memory device: Think "AND = All must be true, OR = Only one needed"
Core Concepts: Loops π
For Loops: Iterate Over Sequences
A for loop repeats code for each item in a sequence (list, string, range, etc.).
Syntax:
for variable in sequence:
# code block executes for each item
The range() function:
range(n)- generates 0 to n-1range(start, stop)- generates start to stop-1range(start, stop, step)- generates with custom step
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(2, 8, 2): # 2, 4, 6
print(i)
π‘ Real-world analogy: A for loop is like a delivery driver with a list of addressesβthey visit each one systematically until the list is complete.
While Loops: Repeat While Condition is True
A while loop continues executing as long as its condition remains True.
Syntax:
while condition:
# code block executes while condition is True
count = 0
while count < 5:
print(count)
count += 1 # IMPORTANT: update the condition variable!
β οΈ Warning: Always ensure your while loop will eventually become False, or you'll create an infinite loop!
Loop Control: break and continue
- break - Exit the loop immediately
- continue - Skip to the next iteration
for i in range(10):
if i == 3:
continue # skip 3
if i == 7:
break # stop at 7
print(i) # prints: 0, 1, 2, 4, 5, 6
Core Concepts: Functions π¦
Function Definitions
A function is a reusable block of code that performs a specific task. Functions help you:
- Organize code into logical units
- Avoid repetition (DRY: Don't Repeat Yourself)
- Make code easier to test and debug
- Enable code reuse across projects
Syntax:
def function_name(parameters):
"""Optional docstring describing the function"""
# code block
return value # optional
Anatomy of a function:
def- keyword to define a functionfunction_name- follows same rules as variable namesparameters- inputs the function accepts (optional)return- sends a value back to the caller (optional)
def greet(name):
"""Greets a person by name"""
return f"Hello, {name}!"
message = greet("Alice") # Call the function
print(message) # Hello, Alice!
Parameters vs Arguments
These terms are often confused:
| Term | Definition | Example |
|---|---|---|
| Parameter | Variable in function definition | def func(x, y): β x, y are parameters |
| Argument | Actual value passed when calling | func(5, 10) β 5, 10 are arguments |
Default Parameters
Parameters can have default values used when no argument is provided:
def power(base, exponent=2):
return base ** exponent
print(power(3)) # 9 (uses default exponent=2)
print(power(3, 3)) # 27 (overrides default)
π‘ Tip: Default parameters must come AFTER non-default parameters!
Return Values
The return statement:
- Sends a value back to the caller
- Immediately exits the function
- Can return multiple values as a tuple
- If omitted, function returns
None
def calculate(a, b):
sum_val = a + b
product = a * b
return sum_val, product # returns tuple
result1, result2 = calculate(5, 3) # unpacking
print(result1, result2) # 8 15
π§ Try this: Write a function that returns nothing but prints. Notice it returns None:
def say_hello():
print("Hello!")
result = say_hello() # prints "Hello!"
print(result) # None
Variable Scope π
Scope determines where a variable can be accessed:
βββββββββββββββββββββββββββββββββββββββ β GLOBAL SCOPE β β (accessible everywhere) β β β β βββββββββββββββββββββββββββββββββ β β β FUNCTION SCOPE β β β β (local to this function) β β β β β β β β βββββββββββββββββββββββββββ β β β β β NESTED FUNCTION SCOPE β β β β β β (innermost scope) β β β β β βββββββββββββββββββββββββββ β β β βββββββββββββββββββββββββββββββββ β βββββββββββββββββββββββββββββββββββββββ
LEGB Rule (scope resolution order):
- Local - inside current function
- Enclosing - in parent function(s)
- Global - at module level
- Built-in - Python's built-in names
x = 10 # global variable
def outer():
x = 20 # enclosing variable
def inner():
x = 30 # local variable
print(x) # 30 (local)
inner()
print(x) # 20 (enclosing)
outer()
print(x) # 10 (global)
π‘ Best practice: Avoid using global variables inside functions. Pass values as parameters instead!
The global keyword: To modify a global variable inside a function:
counter = 0
def increment():
global counter # declare we're using global variable
counter += 1
increment()
print(counter) # 1
Detailed Examples π
Example 1: Grade Calculator with Conditionals
Let's build a function that converts numeric scores to letter grades:
def get_letter_grade(score):
"""
Converts numeric score (0-100) to letter grade.
Args:
score: int or float between 0 and 100
Returns:
str: Letter grade (A, B, C, D, or F)
"""
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
# Test the function
print(get_letter_grade(95)) # A
print(get_letter_grade(82)) # B
print(get_letter_grade(55)) # F
How it works:
- Function accepts a
scoreparameter - Checks conditions from highest to lowest
- Returns immediately when first condition is True
- The
elsecatches all remaining cases (score < 60)
π€ Did you know? The order of conditions matters! If we checked score >= 60 first, a score of 95 would return "D" because 95 is indeed >= 60.
Enhanced version with input validation:
def get_letter_grade(score):
"""Converts score to letter grade with validation"""
if score < 0 or score > 100:
return "Invalid score"
elif score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
print(get_letter_grade(105)) # Invalid score
print(get_letter_grade(-5)) # Invalid score
Example 2: Factorial Calculator with While Loop
Calculate factorial (n! = n Γ (n-1) Γ ... Γ 2 Γ 1):
def factorial(n):
"""
Calculates factorial using while loop.
Args:
n: non-negative integer
Returns:
int: factorial of n
"""
if n < 0:
return None # undefined for negative numbers
result = 1
current = n
while current > 1:
result *= current
current -= 1
return result
# Test
print(factorial(5)) # 120 (5 Γ 4 Γ 3 Γ 2 Γ 1)
print(factorial(0)) # 1 (by definition)
print(factorial(-3)) # None
Step-by-step execution for factorial(5):
| Iteration | current | result | Operation |
|---|---|---|---|
| Start | 5 | 1 | Initialize |
| 1 | 5 | 5 | 1 Γ 5 = 5 |
| 2 | 4 | 20 | 5 Γ 4 = 20 |
| 3 | 3 | 60 | 20 Γ 3 = 60 |
| 4 | 2 | 120 | 60 Γ 2 = 120 |
| End | 1 | 120 | Loop exits (1 not > 1) |
Alternative with for loop:
def factorial(n):
"""Calculates factorial using for loop"""
if n < 0:
return None
result = 1
for i in range(2, n + 1):
result *= i
return result
π‘ Which is better? The for loop version is more Pythonic and concise. Use for loops when you know how many iterations you need, while loops when you don't.
Example 3: List Processing with Multiple Functions
Let's build a system to analyze a list of numbers:
def calculate_average(numbers):
"""
Calculates the average of a list of numbers.
Args:
numbers: list of int or float
Returns:
float: average value, or 0 if list is empty
"""
if len(numbers) == 0:
return 0
total = 0
for num in numbers:
total += num
return total / len(numbers)
def find_maximum(numbers):
"""
Finds the largest number in a list.
Args:
numbers: list of int or float
Returns:
int/float: maximum value, or None if empty
"""
if len(numbers) == 0:
return None
max_value = numbers[0] # assume first is max
for num in numbers:
if num > max_value:
max_value = num
return max_value
def count_above_threshold(numbers, threshold):
"""
Counts how many numbers exceed a threshold.
Args:
numbers: list of int or float
threshold: the cutoff value
Returns:
int: count of numbers above threshold
"""
count = 0
for num in numbers:
if num > threshold:
count += 1
return count
# Using the functions together
scores = [85, 92, 78, 90, 88, 76, 95]
avg = calculate_average(scores)
max_score = find_maximum(scores)
count_a = count_above_threshold(scores, 90)
print(f"Average: {avg:.2f}") # Average: 86.29
print(f"Highest: {max_score}") # Highest: 95
print(f"A grades (>90): {count_a}") # A grades (>90): 2
Design principles demonstrated:
- Single Responsibility: Each function does ONE thing well
- Reusability: Functions can be used independently or together
- Defensive Programming: Check for empty lists
- Clear Documentation: Docstrings explain purpose, args, returns
π Real-world connection: This pattern is used in data analysis, financial reporting, student grade systems, and analytics dashboards everywhere!
Example 4: Nested Loops for Pattern Generation
Create a multiplication table using nested loops:
def print_multiplication_table(size):
"""
Prints a multiplication table up to size Γ size.
Args:
size: int, the dimensions of the table
"""
# Print header row
print(" ", end="")
for i in range(1, size + 1):
print(f"{i:4}", end="")
print() # newline
print(" " + "β" * (size * 4)) # separator line
# Print each row
for row in range(1, size + 1):
print(f"{row:2} β", end="")
for col in range(1, size + 1):
product = row * col
print(f"{product:4}", end="")
print() # newline after each row
# Generate 5Γ5 table
print_multiplication_table(5)
Output:
1 2 3 4 5
ββββββββββββββββββββ
1 β 1 2 3 4 5
2 β 2 4 6 8 10
3 β 3 6 9 12 15
4 β 4 8 12 16 20
5 β 5 10 15 20 25
How nested loops work:
Outer loop (row=1):
Inner loop: col=1,2,3,4,5 β prints 1,2,3,4,5
Outer loop (row=2):
Inner loop: col=1,2,3,4,5 β prints 2,4,6,8,10
Outer loop (row=3):
Inner loop: col=1,2,3,4,5 β prints 3,6,9,12,15
...
π‘ Key insight: The inner loop completes ALL iterations for EACH iteration of the outer loop.
Pattern variations:
def print_triangle(height):
"""Prints a right triangle of asterisks"""
for row in range(1, height + 1):
for col in range(row):
print("*", end="")
print() # newline
print_triangle(5)
# Output:
# *
# **
# ***
# ****
# *****
Common Mistakes β οΈ
1. Indentation Errors
β Wrong:
def greet(name):
print(f"Hello, {name}") # IndentationError!
β Right:
def greet(name):
print(f"Hello, {name}") # properly indented
Fix: Always indent code blocks with 4 spaces (or 1 tab, but be consistent).
2. Using Assignment (=) Instead of Comparison (==)
β Wrong:
if x = 5: # SyntaxError: assigns instead of compares
print("x is 5")
β Right:
if x == 5: # compares x with 5
print("x is 5")
Fix: Remember: = assigns, == compares!
3. Forgetting the Colon (:)
β Wrong:
if x > 10 # SyntaxError: missing colon
print("Large")
def calculate(x) # SyntaxError: missing colon
return x * 2
β Right:
if x > 10: # colon required
print("Large")
def calculate(x): # colon required
return x * 2
Fix: All control flow statements and function definitions end with :
4. Infinite Loops
β Wrong:
count = 0
while count < 5:
print(count)
# Forgot to increment count - runs forever!
β Right:
count = 0
while count < 5:
print(count)
count += 1 # update condition variable
Fix: Always ensure your loop condition will eventually become False!
5. Modifying Global Variables Without 'global' Keyword
β Wrong:
counter = 0
def increment():
counter += 1 # UnboundLocalError!
increment()
β Right:
counter = 0
def increment():
global counter # declare global usage
counter += 1
increment()
Better: Pass as parameter and return:
def increment(counter):
return counter + 1
counter = 0
counter = increment(counter)
6. Returning Inside a Loop Prematurely
β Wrong:
def find_even(numbers):
for num in numbers:
if num % 2 == 0:
return num # returns first even, not all
return None
result = find_even([1, 3, 4, 6, 8])
print(result) # 4 only, not [4, 6, 8]
β Right (if you want all evens):
def find_all_evens(numbers):
evens = []
for num in numbers:
if num % 2 == 0:
evens.append(num)
return evens
result = find_all_evens([1, 3, 4, 6, 8])
print(result) # [4, 6, 8]
7. Off-by-One Errors with range()
β Wrong:
for i in range(10): # 0 to 9, NOT 1 to 10
print(i) # prints 0,1,2,3,4,5,6,7,8,9
β Right (if you want 1-10):
for i in range(1, 11): # 1 to 10
print(i) # prints 1,2,3,4,5,6,7,8,9,10
Remember: range(n) generates 0 to n-1, range(start, stop) generates start to stop-1
8. Not Returning a Value
β Wrong:
def add(a, b):
result = a + b
# forgot return statement
total = add(5, 3)
print(total) # None
β Right:
def add(a, b):
result = a + b
return result # or: return a + b
total = add(5, 3)
print(total) # 8
Key Takeaways π―
β Control Flow:
- Use
if/elif/elsefor decisions based on conditions - Conditions evaluate to Boolean values (True/False)
- Indentation defines code blocks
- Logical operators (
and,or,not) combine conditions
β Loops:
forloops iterate over sequences (lists, strings, ranges)whileloops continue until condition becomes Falsebreakexits loop immediately,continueskips to next iteration- Always ensure while loops will eventually terminate
β Functions:
- Define with
def function_name(parameters): - Parameters are inputs, arguments are actual values passed
- Use
returnto send values back to caller - Functions without
returnimplicitly returnNone - Write docstrings to document purpose, parameters, and return values
β Scope:
- Variables have limited scope (local, enclosing, global, built-in)
- Local variables exist only within their function
- Use
globalkeyword to modify global variables (but avoid when possible) - Pass values as parameters instead of using globals
β Best Practices:
- Keep functions small and focused (single responsibility)
- Use descriptive function and variable names
- Add input validation to functions
- Write docstrings for documentation
- Prefer for loops when iteration count is known
- Test functions with various inputs including edge cases
π Further Study
- Python Official Tutorial - Control Flow: https://docs.python.org/3/tutorial/controlflow.html
- Real Python - Python Functions: https://realpython.com/defining-your-own-python-function/
- Python Official Documentation - Built-in Functions: https://docs.python.org/3/library/functions.html
π Quick Reference Card
| Concept | Syntax | Example |
|---|---|---|
| If Statement | if condition: | if x > 5: print("big") |
| If-Elif-Else | if...elif...else: | if x > 10: ... elif x > 5: ... else: ... |
| For Loop | for var in seq: | for i in range(5): print(i) |
| While Loop | while condition: | while x < 10: x += 1 |
| Break | break | Exit loop immediately |
| Continue | continue | Skip to next iteration |
| Function | def name(params): | def add(x, y): return x + y |
| Return | return value | return x * 2 |
| Default Param | def f(x=0): | def greet(name="World"): ... |
| Global Variable | global var | global counter |
Comparison Operators: == equal, != not equal, < less, > greater, <= less/equal, >= greater/equal
Logical Operators: and (both true), or (at least one true), not (invert)
Range Function: range(n) β 0 to n-1, range(start, stop) β start to stop-1, range(start, stop, step)
LEGB Scope Order: Local β Enclosing β Global β Built-in
Practice makes perfect! π Experiment with these concepts in your Python environment. Try modifying the examples, create your own functions, and challenge yourself with increasingly complex control flow logic. The more you code, the more natural these patterns will become!