Pure Functions in Python
A practical guide to writing predictable, testable code
CORE CONCEPT
What Makes a Function Pure?
A pure function follows two simple rules
that make your code more predictable and
easier to test.
Same Input = Same Output
Given the same arguments, always
returns the same result
No Side Effects
Doesn't modify external state or
variables outside its scope
Pure Function Example
This function is pure because it only depends on its input parameters and doesn't modify anything outside itself.
def calculate_total(price, tax_rate):
"""Pure function: predictable and side-effect free"""
return price + (price * tax_rate)
# Always returns the same result
result1 = calculate_total(100, 0.08) # 108.0
result2 = calculate_total(100, 0.08) # 108.0
The function creates no surprises - same inputs always produce identical outputs, making testing straightforward.
PURE ALTERNATIVE
Making It Pure
Transform impure functions into pure ones by returning new values instead of modifying existing state.
def process_order_pure(order_list, item):
"""Pure version: returns new list"""
return order_list + [item]
# Original list remains unchanged
my_orders = ['book', 'pen']
new_orders = process_order_pure(my_orders, 'notebook')
print(my_orders) # ['book', 'pen'] - unchanged!
print(new_orders) # ['book', 'pen', 'notebook']
The pure version creates predictable behavior - the original data stays intact while new data is returned.
Why Pure Functions Matter
Easy to Test Highly Reusable Parallel-Friendly Predictable Behavior
No setup or teardown needed No hidden dependencies Safe to run concurrently since Easy to understand and debug
- just call the function and mean you can use them they don't share or modify - no mysterious state changes
check the output anywhere without surprises state
When Pure Functions Aren't Possible
Database Queries
File I/O
Real applications need side effects for
useful work. The goal isn't to eliminate all
impure functions, but to isolate them.
User Input
Keep I/O at Edges Pure Core Logic
Push file and database operations to the boundaries of your Make your business logic pure, even if the surrounding
application code isn't
Best Practices
01 02 03
Avoid Global Variables Return New Values Use Immutable Data
Pass data as parameters instead of Create and return new objects rather than Prefer tuples and frozen dataclasses
accessing global state modifying inputs when possible
04 05
Separate Concerns Document Side Effects
Keep pure computation separate from I/O and side effects Clearly mark functions that aren't pure in your documentation
Key Takeaways
Two Simple Rules Big Benefits
Same inputs = same outputs, no Easier testing, debugging, and
side effects reasoning about code
Practical Balance
Maximize purity where possible, isolate impurity when necessary