Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Вычисляемые поля: @computed_field
computed_fields

Вычисляемые поля: @computed_field

Создание полей, вычисляемых на лету, кэширование, зависимости между полями.

Вычисляемые поля: @computed_field

Вычисляемые поля позволяют добавлять в модель данные, которые вычисляются на лету при сериализации

#Базовое использование @computed_field

@computed_field создаёт поле, значение которого вычисляется при сериализации:

from pydantic import BaseModel, computed_field class Rectangle(BaseModel): width: float height: float @computed_field @property def area(self) -> float: return self.width * self.height @computed_field @property def perimeter(self) -> float: return 2 * (self.width + self.height) rect = Rectangle(width=10, height=5) # Доступ как к обычному атрибуту print(rect.area) # 50.0 # Вычисляемые поля включаются в сериализацию print(rect.model_dump()) # {'width': 10.0, 'height': 5.0, 'area': 50.0, 'perimeter': 100.0}

Важно:

  • Метод должен быть помечен @property
  • Нужна аннотация возвращаемого типа
  • Поле вычисляется при каждом обращении (если не кэшировать)

#Кэширование вычисляемых полей

По умолчанию вычисляемое поле вычисляется при каждом обращении. Для кэширования:

from functools import cached_property from pydantic import BaseModel, computed_field class Expensive(BaseModel): value: int @computed_field @cached_property def expensive_calculation(self) -> int: # Дорогостоящее вычисление import time time.sleep(1) return self.value ** 2 obj = Expensive(value=10) # Первое вычисление (медленно) print(obj.expensive_calculation) # 100 # Второе обращение (мгновенно, из кэша) print(obj.expensive_calculation) # 100

#Вычисляемые поля с зависимостями

class Order(BaseModel): price: float quantity: int discount: float = 0 @computed_field @property def subtotal(self) -> float: return self.price * quantity @computed_field @property def discount_amount(self) -> float: return self.subtotal * self.discount @computed_field @property def total(self) -> float: return self.subtotal - self.discount_amount order = Order(price=100, quantity=2, discount=0.1) print(order.total) # 180.0 (200 - 20)

#Настройка сериализации вычисляемого поля

#exclude: исключение из сериализации

class User(BaseModel): password_hash: str name: str @computed_field(exclude=True) @property def is_admin(self) -> bool: return self.name == "admin" user = User(password_hash="...", name="alice") # is_admin не включается в сериализацию data = user.model_dump() # {'password_hash': '...', 'name': 'alice'}

#alias: алиас для вычисляемого поля

class Product(BaseModel): price: float quantity: int @computed_field(alias="totalValue") @property def total_value(self) -> float: return self.price * self.quantity product = Product(price=10, quantity=5) # С алиасом data = product.model_dump(by_alias=True) # {'price': 10.0, 'quantity': 5, 'totalValue': 50.0}

#return_type: явное указание типа

from datetime import datetime class Event(BaseModel): start: datetime end: datetime @computed_field(return_type=float) @property def duration_hours(self) -> float: delta = self.end - self.start return delta.total_seconds() / 3600

#Условные вычисляемые поля

from typing import Optional class Employee(BaseModel): name: str salary: float bonus: Optional[float] = None @computed_field @property def total_compensation(self) -> float: return self.salary + (self.bonus or 0) @computed_field @property def has_bonus(self) -> bool: return self.bonus is not None and self.bonus > 0 emp1 = Employee(name="Alice", salary=50000) emp2 = Employee(name="Bob", salary=60000, bonus=10000) print(emp1.total_compensation) # 50000 print(emp1.has_bonus) # False print(emp2.total_compensation) # 60000 + 10000 = 70000 print(emp2.has_bonus) # True

#Вычисляемые поля со сложной логикой

from datetime import datetime, date from typing import List class Subscription(BaseModel): plan: str # "basic", "pro", "enterprise" start_date: date end_date: date features: list[str] @computed_field @property def duration_days(self) -> int: return (self.end_date - self.start_date).days @computed_field @property def is_active(self) -> bool: return date.today() <= self.end_date @computed_field @property def features_count(self) -> int: return len(self.features) @computed_field @property def plan_tier(self) -> str: tiers = { "basic": "Tier 1", "pro": "Tier 2", "enterprise": "Tier 3" } return tiers.get(self.plan, "Unknown") sub = Subscription( plan="pro", start_date=date(2026, 1, 1), end_date=date(2026, 12, 31), features=["api", "support", "analytics"] ) print(sub.duration_days) # 364 print(sub.is_active) # True/False в зависимости от даты print(sub.features_count) # 3 print(sub.plan_tier) # "Tier 2"

#Вычисляемые поля и валидация

Вычисляемые поля не участвуют в валидации — они вычисляются после:

class Data(BaseModel): value: int @computed_field @property def doubled(self) -> int: return self.value * 2 # Валидация проходит только для value data = Data(value="10") # строка преобразуется в int print(data.doubled) # 20

#Мини-проект: Модель банковского счёта

Создайте модель BankAccount с вычисляемыми полями:

from pydantic import BaseModel, Field, computed_field from datetime import date from typing import List from decimal import Decimal class Transaction(BaseModel): amount: Decimal description: str date: date is_debit: bool # True для расхода, False для дохода class BankAccount(BaseModel): account_number: str owner: str transactions: list[Transaction] = Field(default_factory=list) # Добавьте вычисляемые поля: # 1. balance — текущий баланс (доходы - расходы) # 2. total_debits — сумма всех расходов # 3. total_credits — сумма всех доходов # 4. transaction_count — количество транзакций # 5. is_overdrawn — True если баланс отрицательный pass # Пример: account = BankAccount( account_number="123456789", owner="Alice", transactions=[ Transaction(amount=Decimal("1000.00"), description="Salary", date=date(2026, 1, 1), is_debit=False), Transaction(amount=Decimal("200.00"), description="Rent", date=date(2026, 1, 5), is_debit=True), Transaction(amount=Decimal("50.00"), description="Groceries", date=date(2026, 1, 10), is_debit=True) ] ) print(account.balance) # 1000 - 200 - 50 = 750 print(account.total_debits) # 250 print(account.total_credits) # 1000 print(account.is_overdrawn) # False

Далее: Конфигурация моделей: ConfigDict