Chapter 9: Functions: Reusable Code 🔧
Imagine you need to calculate the area of a rectangle in your program 10 different times. You could write length * width every single time, but what if you make a mistake in one place? What if the formula needs to change?
Functions solve this problem. They let you write code once and reuse it as many times as you need. You’ve already been using built-in functions like print(), len(), and input(). Now it’s time to create your own!
By the end of this chapter, you’ll be able to write cleaner, more organized code by breaking complex programs into smaller, reusable pieces.
What are Functions? 🎯
A function is a named block of code that performs a specific task. Think of it as a mini-program within your program. You define it once, then “call” (use) it whenever you need it.
Why Use Functions?
Functions provide several benefits:
1. Avoid Repetition (DRY - Don’t Repeat Yourself)
# Without functions - repetitive
print("=" * 40)
print("Welcome to the Game!")
print("=" * 40)
# Later in the program...
print("=" * 40)
print("Welcome to the Game!")
print("=" * 40)
# And again...
print("=" * 40)
print("Welcome to the Game!")
print("=" * 40)
# With functions - clean and reusable
def show_header():
print("=" * 40)
print("Welcome to the Game!")
print("=" * 40)
show_header() # Use it once
# ... other code ...
show_header() # Use it again
# ... other code ...
show_header() # And again
2. Organize Your Code
Functions help you break large programs into logical pieces, making them easier to understand and maintain.
3. Fix Bugs in One Place
If there’s an error in your code, you only need to fix it once in the function, not everywhere you used it.
4. Make Code Readable
Well-named functions make your code self-documenting:
calculate_total_price(items, tax_rate) # Clear what this does
validate_email(user_input) # Obvious purpose
send_welcome_message(username) # Easy to understand
Defining and Calling Functions 📝
Creating a function has two steps: defining it (writing what it does) and calling it (using it).
Basic Syntax
def function_name():
# Code to execute
print("This is inside the function")
The structure:
- Start with
def(short for “define”) - Give it a name (follow variable naming rules)
- Add parentheses
() - End with a colon
: - Indent the code that belongs to the function
A Simple Example
# Define the function
def say_hello():
print("Hello!")
print("How are you today?")
# Call the function
say_hello()
Output:
Hello!
How are you today?
Calling Multiple Times
Once defined, you can call a function as many times as you want:
def show_message():
print("Python is awesome!")
show_message()
show_message()
show_message()
Output:
Python is awesome!
Python is awesome!
Python is awesome!
Functions Don’t Run Until Called
Important: defining a function doesn’t execute its code. The code only runs when you call it:
def greet():
print("Hello!")
# Nothing happens yet - just defined
print("Starting program") # This prints
greet() # NOW the function runs
print("Ending program") # This prints too
Output:
Starting program
Hello!
Ending program
Practical Example
def display_menu():
print("\n=== Main Menu ===")
print("1. New Game")
print("2. Load Game")
print("3. Settings")
print("4. Exit")
print("=" * 17)
# Use the function
display_menu()
choice = input("Choose an option: ")
if choice == "1":
print("Starting new game...")
# Later you might show the menu again
display_menu()
Function Parameters 📥
Functions become much more powerful when they can accept parameters (also called arguments) — values you pass in to customize what the function does.
Basic Parameters
def greet(name):
print(f"Hello, {name}!")
print("Welcome to our program!")
greet("Alice") # Shows: Hello, Alice!
greet("Bob") # Shows: Hello, Bob!
greet("Charlie") # Shows: Hello, Charlie!
The name inside the parentheses is a parameter — a variable that receives the value you pass in.
How Parameters Work
When you call the function, the value you provide is assigned to the parameter:
def welcome(username):
# 'username' becomes "Alex" when we call welcome("Alex")
print(f"Welcome, {username}!")
welcome("Alex") # username = "Alex"
Multiple Parameters
Functions can accept multiple parameters, separated by commas:
def introduce(name, age, hobby):
print(f"Hi! My name is {name}.")
print(f"I'm {age} years old.")
print(f"I love {hobby}!")
introduce("Jordan", 14, "gaming")
Output:
Hi! My name is Jordan.
I'm 14 years old.
I love gaming!
The order matters — the first value goes to the first parameter, second to second, etc.
Practical Examples
Example 1: Calculate rectangle area
def calculate_area(length, width):
area = length * width
print(f"A rectangle {length} x {width} has area: {area}")
calculate_area(5, 3) # Shows: 15
calculate_area(10, 7) # Shows: 70
calculate_area(4, 4) # Shows: 16
Example 2: Display formatted message
def show_score(player_name, points, level):
print("=" * 40)
print(f"Player: {player_name}")
print(f"Score: {points}")
print(f"Level: {level}")
print("=" * 40)
show_score("DragonSlayer", 1500, 8)
show_score("CodeMaster", 2300, 12)
Example 3: Personalized greeting
def greet_user(name, time_of_day):
print(f"Good {time_of_day}, {name}!")
print("How can I help you today?")
greet_user("Alice", "morning")
greet_user("Bob", "afternoon")
greet_user("Charlie", "evening")
Default Parameter Values
You can give parameters default values that are used if no argument is provided:
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Alice") # Shows: Hello, Alice!
greet("Bob", "Hi") # Shows: Hi, Bob!
greet("Charlie", "Welcome") # Shows: Welcome, Charlie!
Default parameters must come after non-default ones:
# Correct
def create_user(username, role="user", active=True):
print(f"Created {username} as {role}, Active: {active}")
# Wrong - will cause an error
# def create_user(username="guest", role, active=True):
Return Values 🔄
So far, our functions have printed output. But often you want a function to calculate something and give the result back to use elsewhere. That’s what the return statement does.
Basic Return
def add(a, b):
result = a + b
return result
total = add(5, 3)
print(total) # Shows: 8
The return statement:
- Sends a value back to where the function was called
- Immediately exits the function
Using Return Values
Once a function returns a value, you can use it like any other value:
def multiply(x, y):
return x * y
# Use in a variable
product = multiply(4, 7)
print(product) # Shows: 28
# Use in calculations
result = multiply(3, 5) + multiply(2, 4)
print(result) # Shows: 15 + 8 = 23
# Use in conditions
if multiply(2, 3) > 5:
print("Greater than 5!")
# Use in f-strings
print(f"4 times 6 is {multiply(4, 6)}")
Return vs Print
This is a common confusion for beginners:
# This PRINTS - you see output but can't use the value
def add_and_print(a, b):
result = a + b
print(result)
add_and_print(5, 3) # Shows: 8
# But you can't do: total = add_and_print(5, 3) + 10
# This RETURNS - you get the value to use
def add_and_return(a, b):
result = a + b
return result
total = add_and_return(5, 3) + 10
print(total) # Shows: 18
Use return when you want to use the result. Use print() when you just want to show information.
Returning Multiple Values
Python lets you return multiple values as a tuple:
def get_stats(numbers):
total = sum(numbers)
count = len(numbers)
average = total / count
return total, count, average
scores = [85, 92, 78, 95, 88]
sum_score, num_scores, avg_score = get_stats(scores)
print(f"Total: {sum_score}")
print(f"Count: {num_scores}")
print(f"Average: {avg_score:.1f}")
Early Return
You can use return to exit a function early:
def divide(a, b):
if b == 0:
print("Error: Cannot divide by zero!")
return None # Exit early
return a / b
result = divide(10, 2)
print(result) # Shows: 5.0
result = divide(10, 0)
print(result) # Shows: None
Practical Examples
Example 1: Temperature converter
def celsius_to_fahrenheit(celsius):
fahrenheit = (celsius * 9/5) + 32
return fahrenheit
temp_c = 25
temp_f = celsius_to_fahrenheit(temp_c)
print(f"{temp_c}°C = {temp_f}°F")
Example 2: Price calculator
def calculate_total(price, quantity, tax_rate=0.08):
subtotal = price * quantity
tax = subtotal * tax_rate
total = subtotal + tax
return total
item_price = 19.99
item_qty = 3
final_price = calculate_total(item_price, item_qty)
print(f"Total: ${final_price:.2f}")
Example 3: Grade calculator
def calculate_grade(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
student_score = 87
grade = calculate_grade(student_score)
print(f"Score {student_score} = Grade {grade}")
Scope: Local vs Global Variables 🌍
Variables have scope — where they can be accessed in your code. Understanding scope helps you avoid bugs and write better functions.
Local Scope
Variables created inside a function only exist within that function:
def my_function():
message = "Hello from inside!" # Local variable
print(message)
my_function()
# print(message) # ERROR: message doesn't exist here
Global Scope
Variables created outside functions are global — accessible everywhere:
game_title = "Space Adventure" # Global variable
def show_title():
print(game_title) # Can access global variable
show_title() # Shows: Space Adventure
print(game_title) # Shows: Space Adventure
Parameters Are Local
Function parameters are local variables:
def greet(name): # 'name' is local
print(f"Hello, {name}!")
greet("Alice")
# print(name) # ERROR: name doesn't exist outside function
Best Practice: Avoid Global Variables
It’s better to pass values as parameters and return results:
# Less ideal - using global variable
total_score = 0
def add_points(points):
global total_score # Needed to modify global
total_score += points
# Better - using parameters and return
def add_points(current_score, points):
return current_score + points
total_score = 0
total_score = add_points(total_score, 100)
The second approach is clearer and less error-prone.
Function Examples and Patterns 💡
Let’s look at common patterns and practical function examples.
Pattern 1: Validation Functions
def is_valid_age(age):
return 0 < age < 120
def is_valid_email(email):
return "@" in email and "." in email
# Use them
user_age = int(input("Enter your age: "))
if is_valid_age(user_age):
print("Valid age!")
else:
print("Invalid age!")
Pattern 2: Formatting Functions
def format_currency(amount):
return f"${amount:.2f}"
def format_percentage(value):
return f"{value * 100:.1f}%"
price = 49.99
discount = 0.15
print(f"Price: {format_currency(price)}")
print(f"Discount: {format_percentage(discount)}")
Pattern 3: Menu Display Functions
def show_main_menu():
print("\n" + "=" * 30)
print(" MAIN MENU")
print("=" * 30)
print("1. Start Game")
print("2. Settings")
print("3. Quit")
print("=" * 30)
def get_menu_choice(min_option, max_option):
while True:
choice = input(f"Enter choice ({min_option}-{max_option}): ")
if choice.isdigit():
num = int(choice)
if min_option <= num <= max_option:
return num
print("Invalid choice. Try again.")
Pattern 4: Calculation Functions
def calculate_bmi(weight_kg, height_m):
bmi = weight_kg / (height_m ** 2)
return round(bmi, 1)
def get_bmi_category(bmi):
if bmi < 18.5:
return "Underweight"
elif bmi < 25:
return "Normal"
elif bmi < 30:
return "Overweight"
else:
return "Obese"
# Use together
weight = 70
height = 1.75
bmi_value = calculate_bmi(weight, height)
category = get_bmi_category(bmi_value)
print(f"BMI: {bmi_value} ({category})")
Pattern 5: List Processing Functions
def find_highest(numbers):
if len(numbers) == 0:
return None
highest = numbers[0]
for num in numbers:
if num > highest:
highest = num
return highest
def calculate_average(numbers):
if len(numbers) == 0:
return 0
return sum(numbers) / len(numbers)
scores = [85, 92, 78, 95, 88]
print(f"Highest: {find_highest(scores)}")
print(f"Average: {calculate_average(scores):.1f}")
Quick Recap 🎯
You’ve learned how to create and use functions:
- Define functions with
defand a name - Call functions to execute their code
- Pass parameters to customize function behavior
- Return values to get results from functions
- Understand scope — local vs global variables
- Use common patterns for validation, formatting, and calculations
Functions make your code reusable, organized, and easier to maintain!
Hands-On Mini Project: Calculator Program 🧮
Let’s build a comprehensive calculator using functions to organize different operations.
Your Mission
Create a calculator program that:
- Has separate functions for each operation
- Displays a menu of operations
- Gets user input and performs calculations
- Shows results in a formatted way
- Lets users perform multiple calculations
Example Solution
# Calculator Program with Functions
def add(a, b):
"""Add two numbers and return the result."""
return a + b
def subtract(a, b):
"""Subtract b from a and return the result."""
return a - b
def multiply(a, b):
"""Multiply two numbers and return the result."""
return a * b
def divide(a, b):
"""Divide a by b and return the result."""
if b == 0:
return None # Cannot divide by zero
return a / b
def power(a, b):
"""Raise a to the power of b."""
return a ** b
def percentage(value, percent):
"""Calculate what percentage of value the percent represents."""
return (value * percent) / 100
def display_menu():
"""Display the calculator menu."""
print("\n" + "=" * 50)
print(" PYTHON CALCULATOR")
print("=" * 50)
print("1. Add")
print("2. Subtract")
print("3. Multiply")
print("4. Divide")
print("5. Power")
print("6. Percentage")
print("7. Exit")
print("=" * 50)
def get_number(prompt):
"""Get a number from the user with validation."""
while True:
try:
return float(input(prompt))
except ValueError:
print("Invalid input. Please enter a number.")
def format_result(operation, num1, num2, result):
"""Format and display the result."""
print("\n" + "-" * 50)
if result is None:
print("ERROR: Cannot divide by zero!")
else:
print(f"Result: {result}")
print(f"Calculation: {num1} {operation} {num2} = {result}")
print("-" * 50)
# Main program
def main():
"""Main calculator program loop."""
print("Welcome to the Python Calculator!")
running = True
while running:
display_menu()
choice = input("\nChoose an operation (1-7): ")
if choice == "7":
print("\nThank you for using Python Calculator!")
print("Goodbye! 👋\n")
running = False
continue
if choice not in ["1", "2", "3", "4", "5", "6"]:
print("Invalid choice. Please select 1-7.")
continue
# Get numbers from user
num1 = get_number("Enter first number: ")
num2 = get_number("Enter second number: ")
# Perform calculation based on choice
if choice == "1":
result = add(num1, num2)
format_result("+", num1, num2, result)
elif choice == "2":
result = subtract(num1, num2)
format_result("-", num1, num2, result)
elif choice == "3":
result = multiply(num1, num2)
format_result("×", num1, num2, result)
elif choice == "4":
result = divide(num1, num2)
format_result("÷", num1, num2, result)
elif choice == "5":
result = power(num1, num2)
format_result("^", num1, num2, result)
elif choice == "6":
result = percentage(num1, num2)
print("\n" + "-" * 50)
print(f"{num2}% of {num1} = {result}")
print("-" * 50)
# Run the calculator
main()
Challenge Yourself
Enhance your calculator with these features:
- More operations — Square root, absolute value, rounding
- Memory functions — Store and recall previous results
- History — Keep track of all calculations
- Scientific mode — Add trigonometric functions (sin, cos, tan)
- Unit converter — Convert between units (km/miles, kg/lbs, etc.)
- Expression parser — Let users type “5 + 3 * 2” instead of choosing operations
- Decimal precision — Let users choose how many decimal places to display
- Clear screen — Clear the terminal between operations
- Error messages — More detailed error handling
- Statistics — Calculate mean, median, mode from a list of numbers
Tips for Building
- Keep each function focused on one task
- Use descriptive function names
- Add comments explaining what each function does
- Validate user input before performing operations
- Test edge cases (dividing by zero, negative numbers, etc.)
- Consider using docstrings (the
"""text"""format) to document functions
What’s Next?
In the next chapter, we’ll put everything together! You’ll learn about the random module, debugging basics, and create a Capstone Project: Text Adventure Game that combines all the skills you’ve learned throughout this series.
Get ready for the final challenge!
Fantastic work! Functions are essential for writing professional, maintainable code!