Pure and Impure Functions
Not all functions behave the same way. Some functions take inputs, calculate a result, and return it — nothing else happens. Others print messages, modify lists, or depend on external data. Understanding this distinction helps you write more predictable, testable code.
Pure Functions
A pure function has two characteristics:
- Same input always produces same output — call it with
(3, 5)and you'll always get the same result - No side effects — it doesn't change anything outside itself
def add(a, b):
return a + b
def calculate_area(width, height):
return width * height
These functions are predictable. You can call them a thousand times with the same inputs and always get the same outputs. They don't print anything, modify any lists, or depend on global variables.
Impure Functions
An impure function either produces side effects or depends on external state:
# Side effect: prints to screen
def greet(name):
print(f"Hello, {name}!")
# Side effect: modifies input list
def add_item(shopping_list, item):
shopping_list.append(item)
# Depends on external state
counter = 0
def increment():
global counter
counter = counter + 1
return counter
These functions do more than calculate values. They change things in the outside world or behave differently depending on external conditions.
Why This Matters
Pure functions are easier to test. You just check that inputs produce expected outputs:
# Easy to test
def add(a, b):
return a + b
assert add(2, 3) == 5 # Simple!
Pure functions are easier to understand. You don't need to track what else they might affect.
Pure functions are easier to reuse. They don't depend on specific global variables or system state.
When Impure Is Necessary
Programs need to interact with the world. You have to print output, save files, send network requests, and update databases. These are all side effects, and they're essential.
The goal isn't to eliminate impure functions — it's to be intentional about them. Keep your calculation logic in pure functions, and use impure functions specifically for interacting with the outside world.
# Pure: just calculates
def calculate_total(items):
return sum(item["price"] for item in items)
# Impure: interacts with user
def display_total(total):
print(f"Your total is ${total:.2f}")
# Use them together
total = calculate_total(cart_items) # Pure calculation
display_total(total) # Impure output
This separation makes your code more organized and testable.