Python Functions · Write Reusable Code

Mingming Li — Click any blue heading below to expand the content.

Table of Contents

1. What is a function?

A function is a reusable block of code that performs a specific task. Functions help you organize code, avoid repetition, and make programs easier to read and maintain.

Think of a function like a recipe: it has inputs (ingredients), steps (instructions), and an output (the finished dish).
# Defining a simple function
def greet():
    print("Hello, World!")

# Calling the function
greet()   # Output: Hello, World!

# Function with parameters (inputs)
def greet_person(name):
    print(f"Hello, {name}!")

greet_person("Alice")   # Output: Hello, Alice!
greet_person("Bob")     # Output: Hello, Bob!

# Function with return value (output)
def add(a, b):
    return a + b

result = add(5, 3)
print(result)   # Output: 8
Function syntax: def function_name(parameters): followed by an indented block of code. Use return to send a value back.

2. Function parameters and arguments

# Positional arguments (order matters)
def introduce(name, age, city):
    print(f"{name} is {age} years old and lives in {city}")

introduce("Alice", 25, "New York")

# Default parameter values (optional parameters)
def greet(name="Guest"):
    print(f"Hello, {name}!")

greet()           # Hello, Guest! (uses default)
greet("Alice")    # Hello, Alice! (overrides default)

# Keyword arguments (order doesn't matter when you name them)
introduce(city="Boston", age=30, name="Bob")

# *args - variable number of positional arguments
def sum_all(*numbers):
    total = 0
    for num in numbers:
        total += num
    return total

print(sum_all(1, 2, 3))       # 6
print(sum_all(5, 10, 15, 20)) # 50

# **kwargs - variable number of keyword arguments
def print_info(**info):
    for key, value in info.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=25, city="Boston")
Pro tip: Use default parameters to make arguments optional. Use *args for a list of values, **kwargs for named values.

3. Return values

# Returning a single value
def square(x):
    return x * x

result = square(5)   # 25

# Returning multiple values (as a tuple)
def get_min_max(numbers):
    return min(numbers), max(numbers)

minimum, maximum = get_min_max([3, 1, 7, 4, 9])
print(minimum, maximum)   # 1 9

# Functions without return return None
def say_hello(name):
    print(f"Hello {name}")

value = say_hello("Alice")
print(value)   # None

# Return can exit early (like a guard)
def check_age(age):
    if age < 0:
        return "Invalid age"
    if age < 18:
        return "Too young"
    return "Welcome"

print(check_age(15))  # Too young
print(check_age(25))  # Welcome
Remember: If a function doesn't have a return statement, it returns None. Use return to send data back to the caller.

4. Variable scope (local vs global)

# Local variable (inside function only)
def my_function():
    x = 10   # local variable - only exists inside this function
    print(x)

my_function()
# print(x)   # Error! x is not defined outside

# Global variable (accessible everywhere)
y = 20   # global variable

def print_global():
    print(y)   # can access global variable (read-only)

print_global()   # 20

# Modifying global variables (use 'global' keyword)
counter = 0

def increment():
    global counter   # tell Python we want to modify the global counter
    counter += 1

increment()
increment()
print(counter)   # 2

# Local variables take precedence over global
value = 100

def test():
    value = 50   # this is a NEW local variable
    print(value) # prints 50 (local)

test()        # 50
print(value)  # 100 (global unchanged)
Best practice: Avoid using global when possible. Pass values as parameters and return results instead. This makes code easier to debug and test.

5. Lambda functions (anonymous functions)

A lambda function is a small, anonymous function defined in one line. It's useful for simple operations where a full function would be overkill.

# Basic lambda
square = lambda x: x * x
print(square(5))   # 25

# Lambda with multiple arguments
add = lambda a, b: a + b
print(add(3, 7))   # 10

# Using lambda with map() - apply to every item
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x * x, numbers))
print(squares)   # [1, 4, 9, 16, 25]

# Using lambda with filter() - keep items that match
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)   # [2, 4]

# Using lambda with sort() - custom sorting
students = [("Alice", 85), ("Bob", 92), ("Charlie", 78)]
students.sort(key=lambda student: student[1])  # sort by score
print(students)   # [('Charlie', 78), ('Alice', 85), ('Bob', 92)]
When to use lambda: For simple one-line functions that you use only once. For anything complex, use a regular function with def.

6. Docstrings (documenting functions)

Docstrings are strings that document what your function does. They appear right after the function definition.

def calculate_area(length, width):
    """
    Calculate the area of a rectangle.

    Parameters:
    length (float): The length of the rectangle
    width (float): The width of the rectangle

    Returns:
    float: The area of the rectangle
    """
    return length * width

# View the docstring
help(calculate_area)
print(calculate_area.__doc__)

# A simpler docstring example
def is_prime(n):
    """Return True if n is a prime number, otherwise False."""
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True
Good practice: Always add docstrings to your functions! They help other programmers (and your future self) understand what the function does.

7. Recursion (function calling itself)

Warning: Recursion can be elegant but may cause stack overflow for very deep recursion. Always include a base case to stop recursion!
# Factorial using recursion
# 5! = 5 * 4 * 3 * 2 * 1 = 120
def factorial(n):
    if n == 0 or n == 1:   # base case - stops recursion
        return 1
    else:
        return n * factorial(n - 1)   # recursive case

print(factorial(5))   # 120

# Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21...
def fibonacci(n):
    if n <= 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(7))   # 13

# Countdown example
def countdown(n):
    if n <= 0:
        print("Blast off!")
    else:
        print(n)
        countdown(n - 1)

countdown(5)

8. Quick reference

# DEFINING A FUNCTION
def function_name(parameter1, parameter2):
    # code block
    return result

# CALLING A FUNCTION
function_name(arg1, arg2)

# TYPES OF PARAMETERS
def func(pos1, pos2, default="value", *args, **kwargs):
    pass

# RETURN VALUES
return value           # return a single value
return value1, value2  # return multiple values (as tuple)
return                 # return None

# LAMBDA (one-line function)
lambda x: x * 2

# VARIABLE SCOPE
x = 10                 # local variable (inside function)
global global_var      # declare to modify global variable

# DOCSTRING
def func():
    """Description of what this function does"""

# RECURSION
def recursive_func(n):
    if n <= 0:           # BASE CASE - stops recursion
        return 1
    return n * recursive_func(n - 1)   # RECURSIVE CASE

9. Quick Challenge: Spot the Functions in Our Game

Look at this code from our game. Can you identify the functions?

import pygame

def check_collision(player_rect, cactus_rect):
    if player_rect.colliderect(cactus_rect):
        return True
    return False

def update_score(score):
    score += 1
    return score

def draw_game_over(screen):
    font = pygame.font.Font(None, 36)
    text = font.render("Press SPACE to start", True, (100, 100, 255))
    screen.blit(text, (400, 200))

Questions:

  1. What are the names of the functions defined above?
  2. Which function has parameters? What are they?
  3. Which function returns a value? What does it return?
  4. What would happen if we removed the return from check_collision?
Click for answers
  1. check_collision, update_score, draw_game_over
  2. check_collision has player_rect and cactus_rect; update_score has score; draw_game_over has screen
  3. check_collision returns True or False; update_score returns the new score
  4. It would return None instead of a boolean, and collision detection would break

10. Exercises

Try these exercises to practice functions. Write your code in Thonny.

  • Exercise 1: Write a function greet that takes a name and prints "Hello, [name]!".
  • Exercise 2: Write a function add_numbers that takes two numbers and returns their sum.
  • Exercise 3: Write a function is_even that returns True if a number is even.
  • Exercise 4: Write a function max_of_two that returns the larger of two numbers.
  • Exercise 5: Write a function count_vowels that counts vowels in a string.
  • Exercise 6: Write a function reverse_string that returns a string reversed.
  • Exercise 7: Write a function celsius_to_fahrenheit that converts temperature.
  • Exercise 8: Write a function average that takes a list and returns the average.
  • Exercise 9: Write a function multiply_all that takes any number of arguments and returns their product.
  • Exercise 10: Write a function is_palindrome that checks if a string reads the same forwards and backwards.

11. Common Errors & Solutions

  • IndentationError: expected an indented block
    -> The code inside a function must be indented (usually 4 spaces).
  • NameError: name 'x' is not defined
    -> You're trying to use a variable that doesn't exist or is outside its scope.
  • TypeError: function() missing 1 required positional argument
    -> You forgot to pass all required parameters to the function.
  • RecursionError: maximum recursion depth exceeded
    -> Your recursive function has no base case or the base case never runs.
  • UnboundLocalError: local variable referenced before assignment
    -> You tried to use a local variable before assigning a value to it.
Debugging tip: Use print() statements inside functions to see what values are being passed and what is being returned.

12. Check Your Understanding

  1. What keyword do you use to define a function?
  2. What is the difference between a parameter and an argument?
  3. What does the return statement do?
  4. What does a function return if there is no return statement?
  5. What is a local variable? A global variable?
  6. What is recursion?
Click for Answers
  1. The def keyword
  2. A parameter is a variable in the function definition; an argument is the actual value passed when calling the function.
  3. return sends a value back to the caller and exits the function.
  4. None
  5. A local variable exists only inside a function; a global variable exists everywhere.
  6. Recursion is when a function calls itself. It needs a base case to stop.

13. Your Progress Tracker

Check off each item as you master it:
I can define and call my own functions
I understand parameters and arguments
I can use default parameters
I understand return values
I understand the difference between local and global scope
I can write simple lambda functions
I can add docstrings to my functions
I understand basic recursion
I completed at least 8 exercises