Для чего используется декоратор @computed_field в Pydantic

Ответ

Декоратор @computed_field в Pydantic (начиная с v2) используется для создания вычисляемых полей, значения которых генерируются на основе других полей модели. Эти поля не являются частью входных данных, но включаются в результат сериализации (например, при вызове .model_dump()).

Основные области применения:

  • Производные данные: Создание полей, которые являются результатом вычислений над другими полями (например, full_name из first_name и last_name).
  • Агрегация: Вычисление итоговых значений, таких как общая стоимость или площадь.
  • Форматирование: Представление данных в удобном для вывода формате без изменения исходных полей.

Пример:

from pydantic import BaseModel, computed_field

class Order(BaseModel):
    price: float
    quantity: int

    @computed_field
    @property
    def total_cost(self) -> float:
        """Вычисляет общую стоимость заказа."""
        return self.price * self.quantity

# Создаем экземпляр
order = Order(price=10.5, quantity=4)

# Вычисляемое поле доступно как обычный атрибут
print(order.total_cost)  # Вывод: 42.0

# Поле включается в сериализованный объект
print(order.model_dump())
# Вывод: {'price': 10.5, 'quantity': 4, 'total_cost': 42.0}

Ключевые отличия от стандартного @property:

В отличие от обычного @property, @computed_field полностью интегрируется с экосистемой Pydantic:

  1. Сериализация: Поле автоматически включается в вывод .model_dump() и .model_dump_json().
  2. JSON Schema: Поле попадает в генерируемую JSON Schema, что важно для интеграции с фреймворками вроде FastAPI для автоматической генерации документации.

Ответ 18+ 🔞

А, слушай, смотри, есть в Pydantic такая штука — декоратор @computed_field. Появился со второй версии, ну, чтобы не ебаться с костылями. Суть в чём: ты можешь сделать поле, которое нихуя не приходит извне, а вычисляется на лету из других полей твоей же модели. И главная фишка — оно потом спокойно попадает в JSON при дампе, в документацию API и вообще везде, где надо.

Где это, блядь, пригождается:

  • Производные поля, ёпта. Ну, типа full_name из first_name и last_name. Банально, но нужно.
  • Агрегация какая-нибудь. Посчитать общую сумму заказа, площадь комнаты — всё такое.
  • Форматирование для вывода. Чтобы не портить исходные данные, но на выходе дать красивую строку.

Смотри, как это выглядит вживую:

from pydantic import BaseModel, computed_field

class Order(BaseModel):
    price: float
    quantity: int

    @computed_field
    @property
    def total_cost(self) -> float:
        """Вычисляет общую стоимость заказа."""
        return self.price * self.quantity

# Создаем экземпляр
order = Order(price=10.5, quantity=4)

# Вычисляемое поле доступно как обычный атрибут
print(order.total_cost)  # Вывод: 42.0

# Поле включается в сериализованный объект
print(order.model_dump())
# Вывод: {'price': 10.5, 'quantity': 4, 'total_cost': 42.0}

И вот, блядь, важный момент! Чем это лучше обычного @property?

Да тем, что это не просто геттер, который только в коде живёт. Это полноценное поле Pydantic, ёбта!

  1. Сериализация: Оно автоматом лезет в .model_dump() и .model_dump_json(). Не надо руками его добавлять, ебать мои старые костыли.
  2. JSON Schema: Оно попадает в схему, которую Pydantic генерирует. А это, например, для FastAPI — готовый кусок документации в Swagger. Красота, а не жизнь.

Короче, если раньше ты городил огород с кастомными валидаторами или методами, чтобы поле в вывод просочилось, то теперь — @computed_field и никаких геморроев. Всё чисто, по-взрослому.