
Введение
Декораторы Python сильно упрощают работу над проектами в области ИИ и машинного обучения. Они отделяют ключевую логику — например, создание моделей или обработку данных — от рутинных операций вроде проверок, тестирования, замера времени выполнения или ведения журналов.
Здесь приведены пять проверенных на практике декораторов, которые помогают разработчикам писать более аккуратный код для ИИ.
Примеры используют базовую логику из стандартных библиотек Python и рекомендуемые подходы, включая functools.wraps. Главная цель — показать, как применять каждый декоратор, чтобы вы могли подогнать его под задачи своего ИИ-проекта.
1. Ограничитель параллелизма
Этот декоратор спасает от раздражающих лимитов бесплатных тарифов внешних больших языковых моделей (LLM). Если слишком много асинхронных запросов приводит к блокировкам, декоратор вводит механизм throttling для безопасных вызовов. С помощью семафоров он ограничивает количество одновременных запусков асинхронной функции:
import asyncio
from functools import wraps
def limit_concurrency(limit=5):
sem = asyncio.Semaphore(limit)
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
async with sem:
return await func(*args, **kwargs)
return wrapper
return decorator
# Application
@limit_concurrency(5)
async def fetch_llm_batch(prompt):
return await async_api_client.generate(prompt)
2. Структурированный логгер для ML
В сложных системах машинного обучения простые вызовы print() легко теряются, особенно в продакшене.
Декоратор логирования перехватывает выполнение и ошибки, превращая их в структурированные JSON-записи для быстрого поиска и отладки. Его можно применять, например, к функции обучения эпохи в модели на базе нейросети:
import logging, json, time
from functools import wraps
def json_log(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
try:
res = func(*args, **kwargs)
logging.info(json.dumps({"step": func.__name__, "status": "success", "time": time.time() - start}))
return res
except Exception as e:
logging.error(json.dumps({"step": func.__name__, "error": str(e)}))
raise
return wrapper
# Application
@json_log
def train_epoch(model, training_data):
return model.fit(training_data)
3. Инжектор признаков
Декоратор особенно удобен на этапах развертывания модели и инференса! При переносе модели из Jupyter-ноутбука в легкую прод-окружение, например FastAPI-эндпоинт, вручную применять к сырым данным пользователей те же трансформации, что и к обучающим, бывает хлопотно. Инжектор признаков обеспечивает единообразие генерации фич из исходных данных незаметно для основной логики.
Это критично при деплое и инференсе. Перенос модели из ноутбука в продакшен часто вызывает проблемы с трансформациями пользовательских данных. Декоратор гарантирует, что фичи создаются одинаково до попадания данных в модель.
Пример добавляет фичу 'is_weekend' — проверяет, попадает ли дата из колонки датафрейма на субботу или воскресенье:
from functools import wraps
def add_weekend_feature(func):
@wraps(func)
def wrapper(df, *args, **kwargs):
df = df.copy() # Prevents Pandas mutation warnings
df['is_weekend'] = df['date'].dt.dayofweek.isin([5, 6]).astype(int)
return func(df, *args, **kwargs)
return wrapper
# Application
@add_weekend_feature
def process_data(df):
# 'is_weekend' is guaranteed to exist here
return df.dropna()
4. Фиксатор случайного зерна
Декоратор выделяется для экспериментов и тюнинга гиперпараметров в lifecycle ИИ/ML. Эти этапы часто включают случайное зерно для настройки параметров вроде learning rate модели. Если после изменения точность упала, нужно понять: из-за новой настройки или неудачной инициализации весов? Фиксация сида изолирует переменные, повышая надежность A/B-тестов.
import random, numpy as np
from functools import wraps
def lock_seed(seed=42):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
random.seed(seed)
np.random.seed(seed)
return func(*args, **kwargs)
return wrapper
return decorator
# Application
@lock_seed(42)
def initialize_weights():
return np.random.randn(10, 10)
5. Резервный режим разработки
Спасательный декоратор для локальной разработки и CI/CD-тестов. При построении приложения поверх LLM, например RAG-системы, сбой функции из-за таймаутов или лимитов API вместо исключения возвращает заранее заданные мок-данные.
Почему спасает? Приложение не падает полностью при временных проблемах с внешними сервисами.
from functools import wraps
def fallback_mock(mock_data):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception: # Catches timeouts and rate limits
return mock_data
return wrapper
return decorator
# Application
@fallback_mock(mock_data=[0.01, -0.05, 0.02])
def get_text_embeddings(text):
return external_api.embed(text)
Заключение
Мы разобрали пять эффективных декораторов Python, которые очищают код ИИ и машинного обучения в разных сценариях: от структурированного поиска по логам до контроля случайности для семплирования данных, тестирования и других задач.