Динамическая адаптация награды с помощью Pydantic

от автора

Сегодня разберем тот случай, когда бизнес приходит с очередной задачей, звучащей так: «Нам нужно, чтобы награды для пользователей можно было гибко менять, подстраивать, проверять и, главное, не ломать всё при каждом чихе».

Pydantic — это библиотека для Python, которая превращает данные в нормальные структуры и валидирует их. В отличие от обычных dataclass’ов, он понимает, что данные редко бывают идеальными, и может ловить их на месте.

Например, вот классический кейс:

  • Пользователь совершил действие.

  • На сервер улетает JSON: «я убил дракона, дай мне 100 золотых».

  • Вы проверяете данные, создаете награду, отправляете пользователю.

Идея в том, чтобы не проверять такие данные вручную через if‘ы, а построить модель, которая сама все расскажет. И бонусом — чтобы вся логика не развалилась при следующем обновлении.

Простой пример: валидируем данные награды.

кОfrom pydantic import BaseModel, Field  class Reward(BaseModel):     type: str     amount: int = Field(..., gt=0, description="Количество награды (должно быть больше нуля)")  reward = Reward(type="gold", amount=100) print(reward) 

Код проверяет, что amount больше нуля, а так же генерирует документацию для полей (например, description). Если данные некорректны, бросает исключение.


Пример ситуации

Описываем типы наград

Будет три базовых типа наград:

  1. Золото.

  2. Очки опыта.

  3. Скидки.

Каждый тип имеет свои уникальные параметры. Схема Pydantic для этого:

from typing import Union from pydantic import BaseModel, Field  class GoldReward(BaseModel):     type: str = Field("gold", const=True)     amount: int = Field(..., gt=0, description="Количество золота")  class XPReward(BaseModel):     type: str = Field("xp", const=True)     points: int = Field(..., gt=0, description="Очки опыта")  class DiscountReward(BaseModel):     type: str = Field("discount", const=True)     percentage: float = Field(..., gt=0, lt=100, description="Скидка в процентах")  Reward = Union[GoldReward, XPReward, DiscountReward]

Проверяем данные

Допустим, система присылает JSON с наградой. Pydantic превращает его в объект Python.

reward_data = {"type": "gold", "amount": 150}  # Валидируем и преобразуем try:     reward = Reward.parse_obj(reward_data)     print(reward) except ValidationError as e:     print(f"Ошибка валидации: {e}")

Динамическая адаптация наград

Теперь сделаем адаптер, который меняет награду в зависимости от условий. Например:

  • VIP‑пользователи получают удвоенное золото.

  • Скидки выше 50% требуют дополнительного подтверждения.

class User(BaseModel):     id: int     is_vip: bool = False  class RewardAdapter:     def __init__(self, reward: Reward, user: User):         self.reward = reward         self.user = user      def adapt(self):         if isinstance(self.reward, GoldReward) and self.user.is_vip:             self.reward.amount *= 2         elif isinstance(self.reward, DiscountReward) and self.reward.percentage > 50:             print("Внимание: скидка требует одобрения!")         return self.reward 

Пример использования:

user = User(id=42, is_vip=True) reward_data = {"type": "gold", "amount": 100} reward = Reward.parse_obj(reward_data)  adapter = RewardAdapter(reward, user) adapted_reward = adapter.adapt()  print(adapted_reward)

Добавляем новые типы наград

Что если завтра появляется новый тип награды? Например, «бонусный доступ» к платным функциям. Достаточно просто добавить еще одну модель.

class AccessReward(BaseModel):     type: str = Field("access", const=True)     feature: str = Field(..., description="Название функции")  Reward = Union[GoldReward, XPReward, DiscountReward, AccessReward]

Покрываем тестами

Тесты спасают от сюрпризов. Покажу простой тест на VIP‑адаптацию:

def test_vip_gold_reward():     user = User(id=1, is_vip=True)     reward = GoldReward(type="gold", amount=100)     adapter = RewardAdapter(reward, user)     adapted = adapter.adapt()     assert adapted.amount == 200

Прочая информация

1. А как с безопасностью данных?

Pydantic позволяет строго ограничивать входные данные. Например:

  • Указываем диапазоны (gt=0, lt=100).

  • Используем const=True, чтобы запрещать некорректные типы.

2. Можно ли использовать Pydantic с FastAPI?

Да! FastAPI поддерживает Pydantic для описания запросов и ответов.

3. А если бизнес‑логика станет сложнее?

Добавляйте адаптеры для каждого нового условия. Pydantic позволяет строить вложенные схемы и обрабатывать их в адаптерах.

С прочими возможностями pydantic можно ознакомиться здесь.


17 декабря в рамках курса «Reinforcement Learning» пройдет открытый урок «Алгоритмы с подкреплением в стохастических играх». Узнать подробности и записаться можно по ссылке.


ссылка на оригинал статьи https://habr.com/ru/articles/864178/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *