Programming Fundamentals › Functional Programming
Pure Function
Same input, same output, and no side effects.
Also known as: pure functions, referentially transparent function
A pure function has two properties:
- The same inputs always give the same output.
- It has no side effects: it doesn’t change anything outside itself, or depend on anything that changes.
def add_tax(price, rate):
return price * (1 + rate) # pure
Impure versions:
total = 0
def add_to_total(n):
global total
total += n # changes outside state
def now_plus(days):
return datetime.now() + timedelta(days=days) # depends on the clock
def get_user(id):
return db.query(id) # reads external state
Things that make a function impure: reading or writing globals, files, databases or the network, using the current time or random numbers, printing, and mutating its arguments.
Why prefer them
- Easy to test. Give inputs, check the output, with no setup or mocks (unit tests).
- Easy to reason about. Nothing hidden to track.
- Safe to call twice, cache (memoization), reorder or run in parallel.
- Fewer bugs from shared state (race conditions).
Real programs need impurity
You can’t avoid I/O, since that’s what makes programs useful. The usual design is to keep a pure core of logic and push side effects to the edges: read data, call the pure functions, then write the results (side effects, functional programming).
def decide_discount(order): # pure: easy to test
return 0.1 if order.total > 100 else 0
def checkout(order_id): # impure shell
order = repo.load(order_id)
repo.save_discount(order_id, decide_discount(order))
Passing the time or a random seed in as an argument makes such functions pure again.