In math: (f ∘ g)(x) = f(g(x)) — first g, then f.
What Is Function Composition?
Function composition is the practice of combining simple functions into more complex ones.
In math: (f ∘ g)(x) = f(g(x)) — first g, then f.
def add_10(x):
return x + 10
def multiply_2(x):
return x * 2
# Manual composition: first add_10, then multiply_2
result = multiply_2(add_10(5))
print(result) # 30
# 5 → add_10 → 15 → multiply_2 → 30
Why Use Composition?
Without composition the same pipeline is written out by hand every time:
data1 = step1(raw_data)
data2 = step2(data1)
result = step3(data2)
# For another dataset — again:
data1 = step1(other_data)
data2 = step2(data1)
result = step3(data2)
With composition — define the pipeline once, reuse it everywhere:
process = pipe(step1, step2, step3)
result1 = process(raw_data)
result2 = process(other_data)
result3 = process(more_data)
compose() and pipe()
compose() — right to left
def compose(*functions):
"""Apply functions right to left: f(g(h(x)))."""
def composed(x):
result = x
for func in reversed(functions):
result = func(result)
return result
return composed
def add_10(x):
return x + 10
def multiply_2(x):
return x * 2
def square(x):
return x ** 2
# compose: the last argument runs first
pipeline = compose(square, multiply_2, add_10)
print(pipeline(5)) # 900
# 5 → add_10 → 15 → multiply_2 → 30 → square → 900
Reads right to left (mathematics convention).
pipe() — left to right
def pipe(*functions):
"""Apply functions left to right."""
def piped(x):
result = x
for func in functions:
result = func(result)
return result
return piped
# pipe: the first argument runs first
pipeline = pipe(add_10, multiply_2, square)
print(pipeline(5)) # 900
# 5 → add_10 → 15 → multiply_2 → 30 → square → 900
Reads left to right — more natural for code.
Practical Examples
Example 1: String cleaning
import string
def trim(text):
return text.strip()
def lowercase(text):
return text.lower()
def remove_punctuation(text):
return text.translate(str.maketrans("", "", string.punctuation))
clean_text = pipe(trim, lowercase, remove_punctuation)
dirty = " Hello, World! "
print(clean_text(dirty)) # "hello world"
Example 2: Price calculation
def validate_positive(x):
if x <= 0:
raise ValueError("Must be positive")
return x
def apply_discount(percent):
def discount(price):
return price * (1 - percent / 100)
return discount
def add_tax(percent):
def tax(price):
return price * (1 + percent / 100)
return tax
def round_price(price):
return round(price, 2)
# Pipeline: validate → 20% discount → 10% tax → round
calculate_price = pipe(
validate_positive,
apply_discount(20),
add_tax(10),
round_price
)
print(calculate_price(100)) # 88.0
# 100 → validate → 80 → 88 → 88.0
Decorators Are Composition Too
def uppercase_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs).upper()
return wrapper
def exclaim_decorator(func):
def wrapper(*args, **kwargs):
return f"{func(*args, **kwargs)}!!!"
return wrapper
@exclaim_decorator
@uppercase_decorator
def greet(name):
return f"hello, {name}"
print(greet("Alice")) # "HELLO, ALICE!!!"
# greet → uppercase → exclaim
The decorator stack is applied bottom to top: uppercase_decorator first, then exclaim_decorator.
Common Mistakes
Mistake 1: Wrong argument order
def add_10(x):
return x + 10
def multiply_2(x):
return x * 2
# compose reads RIGHT TO LEFT — multiply_2 runs first!
wrong = compose(add_10, multiply_2)
print(wrong(5)) # 20 (5*2=10, 10+10=20)
# pipe reads LEFT TO RIGHT — add_10 runs first
right = pipe(add_10, multiply_2)
print(right(5)) # 30 ((5+10)*2=30)
Mistake 2: Incompatible function signatures
def add(a, b): # takes 2 arguments
return a + b
def square(x): # takes 1 argument
return x ** 2
# ❌ ERROR: square would receive a tuple instead of a number
# pipeline = pipe(add, square)
# ✅ CORRECT: fix one argument with partial
from functools import partial
add_10 = partial(add, 10)
pipeline = pipe(add_10, square)
print(pipeline(5)) # 225 ((5+10)^2)
Function composition is the foundation of functional style in Python. Use pipe() for readable transformation chains and compose() when mathematical ordering matters.
💬 Comments (0)
No comments yet
Be the first to share your opinion about this article!