Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Каррирование функции (Function Currying)
Каррирование — это техника преобразования функции, которая принимает несколько параметров, в цепочку функций, каждая из которых принимает только один параметр. Получаемые промежуточные функции могут быть сохранены и переиспользованы с разными аргументами.
Термин происходит от имени математика Хаскелла Карри (Haskell Curry).
Основная идея
Обычная функция:
f(a, b, c) → результат
Каррированная функция:
f(a) → g(b) → h(c) → результат
Простой пример
# Обычная функция
def add(a, b, c):
return a + b + c
print(add(1, 2, 3)) # 6
# Каррированная функция
def add_curried(a):
def add_b(b):
def add_c(c):
return a + b + c
return add_c
return add_b
print(add_curried(1)(2)(3)) # 6
# Или более читаемо
add_1 = add_curried(1)
add_1_2 = add_1(2)
result = add_1_2(3)
print(result) # 6
Отличие каррирования от частичного применения
from functools import partial
# Обычная функция
def multiply(a, b, c):
return a * b * c
# Частичное применение (Partial Application)
# Заполняем один параметр, остальные остаются
multiply_by_2 = partial(multiply, 2)
print(multiply_by_2(3, 4)) # 2 * 3 * 4 = 24
multiply_by_2_3 = partial(multiply_by_2, 3)
print(multiply_by_2_3(4)) # 2 * 3 * 4 = 24
# Каррирование
# Преобразуем функцию чтобы она принимала параметры по одному
def multiply_curried(a):
return lambda b: lambda c: a * b * c
print(multiply_curried(2)(3)(4)) # 24
Преимущества каррирования
1. Переиспользование с частичными данными
def multiply_curried(a):
return lambda b: lambda c: a * b * c
# Создаём специализированные функции
double = multiply_curried(2) # multiply by 2
triple = multiply_curried(3) # multiply by 3
# Используем несколько раз
print(double(5)(10)) # 2 * 5 * 10 = 100
print(triple(4)(2)) # 3 * 4 * 2 = 24
2. Композиция функций
def compose(*functions):
def composed(x):
for f in reversed(functions):
x = f(x)
return x
return composed
def add_curry(a):
return lambda x: x + a
def multiply_curry(a):
return lambda x: x * a
# (x * 2) + 5
f = compose(add_curry(5), multiply_curry(2))
print(f(3)) # (3 * 2) + 5 = 11
3. Создание конфигурируемых функций
def logger_curry(level):
return lambda service: lambda message: print(f"[{level}][{service}] {message}")
# Создаём логгеры с разными уровнями
error_logger = logger_curry("ERROR")
warn_logger = logger_curry("WARN")
info_logger = logger_curry("INFO")
# Создаём логгеры для разных сервисов
api_error = error_logger("API")
db_error = error_logger("DB")
# Используем
api_error("Connection timeout") # [ERROR][API] Connection timeout
db_error("Query failed") # [ERROR][DB] Query failed
Автоматическое каррирование
from functools import wraps
def curry(func):
"""Декоратор для автоматического каррирования"""
@wraps(func)
def curried(*args, **kwargs):
if len(args) + len(kwargs) >= func.__code__.co_argcount:
return func(*args, **kwargs)
return lambda *a, **kw: curried(*args, *a, **{**kwargs, **kw})
return curried
@curry
def add(a, b, c, d):
return a + b + c + d
# Можем использовать с разным количеством параметров
print(add(1)(2)(3)(4)) # 10
print(add(1, 2)(3)(4)) # 10
print(add(1, 2, 3)(4)) # 10
print(add(1)(2, 3, 4)) # 10
Практические примеры
1. HTTP запросы
def http_request_curry(method):
return lambda url: lambda headers: lambda data: {
"method": method,
"url": url,
"headers": headers,
"data": data
}
# Создаём специализированные функции
get = http_request_curry("GET")
post = http_request_curry("POST")
# Создаём фиксированные URL конфигурации
api_get = get("https://api.example.com")
api_post = post("https://api.example.com")
# Используем с разными заголовками и данными
request1 = api_get({"Authorization": "Bearer token"})(None)
request2 = api_post({"Content-Type": "application/json"})({"user": "john"})
2. Валидация данных
def validator_curry(field_name):
return lambda field_type: lambda value: {
"field": field_name,
"type": field_type,
"value": value,
"valid": isinstance(value, field_type)
}
# Создаём валидаторы
validate_string = validator_curry("name")(str)
validate_number = validator_curry("age")(int)
# Используем
result1 = validate_string("John") # valid: True
result2 = validate_string(123) # valid: False
result3 = validate_number(25) # valid: True
result4 = validate_number("invalid") # valid: False
3. Цепочка данных (Pipeline)
def pipeline_curry(value):
return lambda func: lambda: func(value)
# Обработка данных
def double(x): return x * 2
def add_ten(x): return x + 10
def square(x): return x * x
# Создаём цепочку
result = 5
result = double(result) # 10
result = add_ten(result) # 20
result = square(result) # 400
print(result) # 400
# Или с использованием каррирования (более функциональный подход)
from functools import reduce
def compose_functions(*funcs):
def composed(x):
return reduce(lambda result, f: f(result), funcs, x)
return composed
pipeline = compose_functions(double, add_ten, square)
print(pipeline(5)) # 400
Каррирование в функциональном программировании
# Функциональный подход к обработке списков
def map_curry(func):
return lambda items: [func(item) for item in items]
def filter_curry(predicate):
return lambda items: [item for item in items if predicate(item)]
def reduce_curry(func):
return lambda acc: lambda items: reduce(func, items, acc)
# Используем
numbers = [1, 2, 3, 4, 5]
double_all = map_curry(lambda x: x * 2)
filter_even = filter_curry(lambda x: x % 2 == 0)
sum_all = reduce_curry(lambda acc, x: acc + x)(0)
# Цепочка обработки
result = sum_all(filter_even(double_all(numbers)))
print(result) # (2 + 4 + 6 + 8 + 10) = 30
Сравнение разных подходов
# Обычная функция
def calculate(operation, a, b):
if operation == "add": return a + b
if operation == "multiply": return a * b
result1 = calculate("add", 5, 3) # Нужно передать операцию каждый раз
# С partial
from functools import partial
add = partial(calculate, "add")
result2 = add(5, 3)
# С каррированием
def calculate_curried(operation):
return lambda a: lambda b: {
"add": a + b,
"multiply": a * b
}[operation]
add_curried = calculate_curried("add")
result3 = add_curried(5)(3)
Когда использовать каррирование
Хорошо для:
- Функциональное программирование
- Создание специализированных функций
- Композиция функций
- Частичное применение
Плохо для:
- Простые задачи
- Когда нужна читаемость
- Высокая производительность
Каррирование — это мощный инструмент функционального программирования, позволяющий создавать гибкие и переиспользуемые функции путём разбиения их на более простые части.