Композиция соединяет небольшие функции в цепочку, где результат одной функции становится аргументом следующей.
Что такое Function Composition?
Function Composition — это комбинирование простых функций в сложные.
В математике: (f ∘ g)(x) = f(g(x)) — сначала g, потом f.
def add_10(x):
return x + 10
def multiply_2(x):
return x * 2
# Композиция вручную: сначала add_10, потом multiply_2
result = multiply_2(add_10(5))
print(result) # 30
# 5 → add_10 → 15 → multiply_2 → 30
Зачем нужна композиция?
Без композиции один и тот же pipeline повторяется вручную:
data1 = step1(raw_data)
data2 = step2(data1)
result = step3(data2)
# Для другого набора — опять:
data1 = step1(other_data)
data2 = step2(data1)
result = step3(data2)
С композицией — создаём pipeline один раз и переиспользуем:
process = pipe(step1, step2, step3)
result1 = process(raw_data)
result2 = process(other_data)
result3 = process(more_data)
compose() и pipe()
compose() — справа налево
def compose(*functions):
"""Применить функции справа налево: 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: последний аргумент выполняется первым
pipeline = compose(square, multiply_2, add_10)
print(pipeline(5)) # 900
# 5 → add_10 → 15 → multiply_2 → 30 → square → 900
Читается справа налево (как в математике).
pipe() — слева направо
def pipe(*functions):
"""Применить функции слева направо."""
def piped(x):
result = x
for func in functions:
result = func(result)
return result
return piped
# pipe: первый аргумент выполняется первым
pipeline = pipe(add_10, multiply_2, square)
print(pipeline(5)) # 900
# 5 → add_10 → 15 → multiply_2 → 30 → square → 900
Читается слева направо — привычнее для кода.
Практические примеры
Пример 1: Очистка строк
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"
Пример 2: Расчёт цены
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: валидация → скидка 20% → налог 10% → округление
calculate_price = pipe(
validate_positive,
apply_discount(20),
add_tax(10),
round_price
)
print(calculate_price(100)) # 88.0
# 100 → проверка → 80 → 88 → 88.0
Декораторы — это тоже композиция
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
Стек декораторов читается снизу вверх: сначала uppercase_decorator, потом exclaim_decorator.
Частые ошибки
Ошибка 1: Неправильный порядок аргументов
def add_10(x):
return x + 10
def multiply_2(x):
return x * 2
# compose читается СПРАВА НАЛЕВО — multiply_2 выполнится первой!
wrong = compose(add_10, multiply_2)
print(wrong(5)) # 20 (5*2=10, 10+10=20)
# pipe читается СЛЕВА НАПРАВО — add_10 выполнится первой
right = pipe(add_10, multiply_2)
print(right(5)) # 30 ((5+10)*2=30)
Ошибка 2: Несовместимые сигнатуры функций
def add(a, b): # принимает 2 аргумента
return a + b
def square(x): # принимает 1 аргумент
return x ** 2
# ❌ ОШИБКА: square получит кортеж вместо числа
# pipeline = pipe(add, square)
# ✅ ПРАВИЛЬНО: зафиксировать один аргумент через partial
from functools import partial
add_10 = partial(add, 10)
pipeline = pipe(add_10, square)
print(pipeline(5)) # 225 ((5+10)^2)
Композиция функций — основа функционального стиля в Python. Используйте pipe() для читаемых цепочек преобразований и compose() когда важен математический порядок.
💬 Комментарии (0)
Комментариев пока нет
Станьте первым, кто поделится мнением об этой статье!