← Назад к вопросам

Какие знаешь элементы функционального программирования в Python?

2.0 Middle🔥 111 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Функциональное программирование в Python

Практически функциональное программирование — парадигма, которая воспринимает вычисления как вычисление математических функций, избегая изменяемого состояния. Python поддерживает множество FP элементов благодаря гибкости языка.

Чистые функции (Pure Functions)

Функции, которые:

  1. Для одного входа всегда возвращают одинаковый выход
  2. Не имеют побочных эффектов (не изменяют внешнее состояние)
# Плохо - не чистая функция
counter = 0
def increment():
    global counter
    counter += 1
    return counter

print(increment())  # 1
print(increment())  # 2
print(increment())  # 3

# Хорошо - чистая функция
def pure_increment(n):
    return n + 1

print(pure_increment(0))  # 1
print(pure_increment(0))  # 1
print(pure_increment(0))  # 1

Преимущества чистых функций:

  • Легче тестировать
  • Кэшируемы (memoization)
  • Параллельно безопасны
  • Проще рассуждать о коде

First-Class Functions (функции как объекты)

Функции можно передавать как аргументы и возвращать из других функций:

# Функция принимает функцию как аргумент
def apply_operation(x, y, operation):
    return operation(x, y)

def add(a, b):
    return a + b

def multiply(a, b):
    return a * b

print(apply_operation(5, 3, add))       # 8
print(apply_operation(5, 3, multiply))  # 15

# Функция возвращает функцию (высший порядок)
def create_multiplier(n):
    def multiplier(x):
        return x * n
    return multiplier

multiply_by_3 = create_multiplier(3)
print(multiply_by_3(10))  # 30

Higher-Order Functions (функции высшего порядка)

map()

Применяет функцию к каждому элементу итерируемого объекта:

numbers = [1, 2, 3, 4, 5]

# Императивный подход
result = []
for num in numbers:
    result.append(num ** 2)

# Функциональный подход
result = list(map(lambda x: x ** 2, numbers))
print(result)  # [1, 4, 9, 16, 25]

# Или с обычной функцией
def square(x):
    return x ** 2

result = list(map(square, numbers))

filter()

Отбирает элементы, для которых функция возвращает True:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Императивный
even = []
for num in numbers:
    if num % 2 == 0:
        even.append(num)

# Функциональный
even = list(filter(lambda x: x % 2 == 0, numbers))
print(even)  # [2, 4, 6, 8, 10]

reduce()

Аккумулирует значения в один результат:

from functools import reduce

numbers = [1, 2, 3, 4, 5]

# Вычисление произведения
product = reduce(lambda x, y: x * y, numbers)
print(product)  # 120

# С начальным значением
total = reduce(lambda x, y: x + y, numbers, 0)
print(total)  # 15

# Практический пример
orders = [100, 200, 150, 300]
total_amount = reduce(lambda sum, order: sum + order, orders, 0)
print(f'Total: ${total_amount}')  # Total: $750

Lambda функции

Анонимные функции для простых операций:

# Простые примеры
square = lambda x: x ** 2
print(square(5))  # 25

# С несколькими аргументами
add = lambda x, y: x + y
print(add(3, 4))  # 7

# Используется с map/filter
nums = [1, 2, 3, 4, 5]
filtered = list(filter(lambda x: x > 2, nums))
print(filtered)  # [3, 4, 5]

# Сортировка по сложному ключу
students = [
    {'name': 'Alice', 'grade': 85},
    {'name': 'Bob', 'grade': 92},
    {'name': 'Charlie', 'grade': 78}
]
sorted_students = sorted(students, key=lambda s: s['grade'], reverse=True)

Closures (замыкания)

Вложенная функция имеет доступ к переменным внешней функции:

def make_adder(x):
    def adder(y):
        return x + y  # Замыкание над 'x'
    return adder

add_5 = make_adder(5)
print(add_5(3))   # 8
print(add_5(10))  # 15

# Практический пример - логирование
def create_logger(prefix):
    def log(message):
        print(f"[{prefix}] {message}")
    return log

error_log = create_logger("ERROR")
info_log = create_logger("INFO")

error_log("Something went wrong")
info_log("Process started")

Decorators

Функции, которые оборачивают другие функции для расширения их поведения:

# Простой декоратор
def timer(func):
    def wrapper(*args, **kwargs):
        import time
        start = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - start
        print(f"{func.__name__} took {elapsed:.4f} seconds")
        return result
    return wrapper

@timer
def slow_function(n):
    import time
    time.sleep(n)
    return f"Done after {n} seconds"

slow_function(1)

# Декоратор с параметрами
def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(times=3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

Immutability (неизменяемость)

Использование неизменяемых структур данных:

# Плохо - мутируемое состояние
config = {'timeout': 30, 'retries': 3}
config['timeout'] = 60  # Изменяем

# Хорошо - неизменяемое состояние
from collections import namedtuple

Config = namedtuple('Config', ['timeout', 'retries'])
config1 = Config(timeout=30, retries=3)
config2 = config1._replace(timeout=60)  # Создаём новый объект

print(config1)  # Config(timeout=30, retries=3)
print(config2)  # Config(timeout=60, retries=3)

# Использование tuples вместо lists
point = (1, 2, 3)  # Неизменяемо
# list_point = [1, 2, 3]  # Мутируемо

Composition (композиция функций)

Объединение простых функций в сложные:

# Функции-кирпичики
def add_tax(price):
    return price * 1.2

def apply_discount(price, discount):
    return price * (1 - discount)

def format_price(price):
    return f"${price:.2f}"

# Композиция
def compose(*functions):
    def composed(arg):
        result = arg
        for func in reversed(functions):
            result = func(result)
        return result
    return composed

# Создание конвейера
final_price = compose(
    format_price,
    add_tax,
    lambda p: apply_discount(p, 0.1)  # 10% скидка
)

original_price = 100
print(final_price(original_price))  # $129.60

Практический пример: Обработка данных

from functools import reduce

# Данные
orders = [
    {'id': 1, 'amount': 100, 'status': 'completed'},
    {'id': 2, 'amount': 200, 'status': 'pending'},
    {'id': 3, 'amount': 150, 'status': 'completed'},
    {'id': 4, 'amount': 300, 'status': 'completed'},
]

# FP подход
total_revenue = reduce(
    lambda sum, order: sum + order['amount'],
    filter(lambda o: o['status'] == 'completed', orders),
    0
)

print(f"Total revenue: ${total_revenue}")  # $550

# Альтернатива с list comprehension (более Pythonic)
total_revenue_v2 = sum(o['amount'] for o in orders if o['status'] == 'completed')
print(f"Total revenue: ${total_revenue_v2}")  # $550

Когда использовать FP в Python

Используй функциональный стиль когда:

  • Нужна параллельная обработка данных
  • Код должен быть предсказуемым и тестируемым
  • Работаешь с трансформациями данных (ETL)
  • Нужна композиция функций

Python лучше всего с гибридным подходом:

# Не переусложняй - Python не 100% FP язык
# Смешивай OOP и FP когда это имеет смысл

class DataProcessor:
    def __init__(self, data):
        self.data = data
    
    def filter_completed(self):
        return list(filter(lambda x: x['status'] == 'completed', self.data))
    
    def sum_amounts(self):
        return reduce(lambda s, x: s + x['amount'], self.data, 0)

Питон поддерживает функциональное программирование как один из инструментов, но язык оптимален с многопарадигмальным подходом, комбинирующим OOP, функциональное и процедурное стили.

Какие знаешь элементы функционального программирования в Python? | PrepBro