📝 Python

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

P
Автор
PyLand Team
📅
Опубликовано
03.04.2026
⏱️
Время чтения
4 мин
👁️
Просмотров
407
🌳
Уровень
Продвинутый

Чистая функция зависит только от аргументов, не меняет внешнее состояние и при одинаковом вводе возвращает одинаковый результат.

Что такое Pure Function?

Pure function (чистая функция) — это функция, которая:
1. Всегда возвращает одинаковый результат при одинаковых аргументах
2. Не имеет побочных эффектов — не изменяет внешнее состояние

# Чистая функция
def add(a, b):
    return a + b

print(add(2, 3))  # 5
print(add(2, 3))  # 5 — всегда одинаково

# Нечистая функция
total = 0

def add_impure(x):
    global total
    total += x      # меняет внешнее состояние!
    return total

print(add_impure(5))  # 5
print(add_impure(5))  # 10 — разный результат!

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

# Математика — чисто
def square(x):
    return x ** 2

def average(numbers):
    return sum(numbers) / len(numbers)

def distance(x1, y1, x2, y2):
    return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5

# Строки — чисто (исходная строка не меняется)
def uppercase(text):
    return text.upper()

def count_vowels(text):
    vowels = "aeiouаеёиоуыэюя"
    return sum(1 for char in text.lower() if char in vowels)

# Списки — чисто (возвращает НОВЫЙ список)
def double_all(numbers):
    return [x * 2 for x in numbers]

def filter_positive(numbers):
    return [x for x in numbers if x > 0]

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

# 1. Изменение глобального состояния
total_score = 0

def add_score_impure(points):     # ❌ нечистая
    global total_score
    total_score += points
    return total_score

def add_score_pure(current_total, points):  # ✅ чистая
    return current_total + points

# 2. Изменение аргументов
def append_impure(lst, item):     # ❌ меняет оригинальный список!
    lst.append(item)
    return lst

def append_pure(lst, item):       # ✅ возвращает новый список
    return lst + [item]

# 3. Побочные эффекты (I/O)
def print_result_impure(x):       # ❌ print — это side effect
    print(f"Result: {x}")
    return x

def format_result_pure(x):        # ✅ возвращает строку — вывод снаружи
    return f"Result: {x}"

# 4. Случайность
import random

def get_random_impure():          # ❌ разный результат каждый раз
    return random.randint(1, 100)

def get_random_pure(seed):        # ✅ одинаковый результат при том же seed
    random.seed(seed)
    return random.randint(1, 100)

Почему Pure Functions хороши?

Предсказуемость и тестируемость

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

# Тест — просто и надёжно
def test_add():
    assert add(2, 3) == 5
    assert add(0, 0) == 0
    assert add(-1, 1) == 0
    # Работает всегда одинаково, без setUp/tearDown

Кэширование (memoization)

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    """Чистая функция — безопасно кэшировать."""
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(100))  # вычисляется
print(fibonacci(100))  # берётся из кэша мгновенно

Безопасный параллелизм

from multiprocessing import Pool

def square(x):
    return x ** 2

with Pool(4) as pool:
    results = pool.map(square, [1, 2, 3, 4, 5])

print(results)  # [1, 4, 9, 16, 25]
# Нет общего состояния — нет гонок данных

Как сделать функцию чистой?

Проблема: глобальная переменная → передать аргументом

# ❌ нечистая
score = 0
def add_points_impure(points):
    global score
    score += points
    return score

# ✅ чистая
def add_points_pure(current_score, points):
    return current_score + points

score = 0
score = add_points_pure(score, 10)  # 10
score = add_points_pure(score, 5)   # 15

Проблема: изменение коллекции → вернуть новую

# ❌ нечистая — меняет оригинал
def sort_impure(numbers):
    numbers.sort()
    return numbers

# ✅ чистая — возвращает новый список
def sort_pure(numbers):
    return sorted(numbers)

original = [3, 1, 2]
sorted_list = sort_pure(original)
print(original)     # [3, 1, 2]  ← не изменился
print(sorted_list)  # [1, 2, 3]
# ❌ нечистая — меняет словарь
def update_age_impure(person, new_age):
    person["age"] = new_age
    return person

# ✅ чистая — возвращает новый словарь
def update_age_pure(person, new_age):
    return {**person, "age": new_age}

person = {"name": "Алиса", "age": 25}
updated = update_age_pure(person, 26)
print(person)   # {'name': 'Алиса', 'age': 25}  ← не изменился
print(updated)  # {'name': 'Алиса', 'age': 26}

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

def get_high_performers(students, threshold=90):
    """Чистая: фильтрация по оценке."""
    return [s for s in students if s["grade"] >= threshold]

def add_status(students):
    """Чистая: добавляет поле без изменения оригинала."""
    return [
        {**s, "status": "Отличник" if s["grade"] >= 90 else "Хорошист"}
        for s in students
    ]

students = [
    {"name": "Алиса", "grade": 95},
    {"name": "Боб", "grade": 87},
    {"name": "Карл", "grade": 92},
]

high_performers = get_high_performers(students, 90)
with_status = add_status(students)

print(high_performers)
# [{'name': 'Алиса', 'grade': 95}, {'name': 'Карл', 'grade': 92}]

print(students[0])
# {'name': 'Алиса', 'grade': 95}  ← поле 'status' не добавлено в оригинал

Частые ошибки

Ошибка 1: Изменение аргумента напрямую

# ❌ мутирует список — вызывающий код не ожидает этого
def add_item_impure(items, new_item):
    items.append(new_item)
    return items

# ✅ создать новый список
def add_item_pure(items, new_item):
    return items + [new_item]

Ошибка 2: Скрытые зависимости от времени или случайности

import time, random

# ❌ нечистые — результат непредсказуем
def get_timestamp():
    return time.time()

def shuffle_data(items):
    random.shuffle(items)   # ещё и мутирует!
    return items

# ✅ принять значение аргументом
def format_timestamp(timestamp):
    return time.strftime("%Y-%m-%d", time.localtime(timestamp))

Ключевое правило: передавайте состояние через аргументы, возвращайте новые данные, не изменяйте старые. Нечистые операции (I/O, БД, сеть) изолируйте в отдельных функциях.

Ваша реакция на статью

💬 Комментарии (0)

🔐 Войдите в систему, чтобы оставить комментарий
🚪 Войти
💭

Комментариев пока нет

Станьте первым, кто поделится мнением об этой статье!

🔗 Похожие

Похожие статьи

Продолжите изучение с этими материалами

📝

Как функции работают вместе в Python 🧩

Небольшая функция обычно решает одну понятную задачу. Но настоящая программа состоит из нескольких задач: получить...

📅 09.08.2026 👁️ 78
📝

map() — Преобразуй каждый элемент!

Функция map() лениво применяет преобразование к каждому элементу итерируемого объекта.

📅 03.04.2026 👁️ 430
📝

filter() — Отбери нужное!

Функция filter() оставляет элементы, для которых проверка возвращает истинное значение.

📅 03.04.2026 👁️ 430

Понравилась статья?

Подпишитесь на наши обновления и получайте новые статьи первыми. Развивайтесь вместе с PyLand!