← Назад к вопросам

Какие знаешь способы реализовать класс по проверки получаемых данных?

2.0 Middle🔥 191 комментариев
#Python Core#REST API и HTTP

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Способы реализации класса для проверки получаемых данных

Валидация входных данных — критически важная часть разработки приложений. Существует несколько подходов к реализации валидаторов в Python.

1. Встроенные типы и try-except

Самый простой способ для базовой валидации:

class SimpleValidator:
    @staticmethod
    def validate_email(email):
        if not isinstance(email, str):
            raise TypeError("Email должен быть строкой")
        if "@" not in email:
            raise ValueError("Некорректный формат email")
        return True
    
    @staticmethod
    def validate_age(age):
        if not isinstance(age, int):
            raise TypeError("Возраст должен быть числом")
        if age < 0 or age > 150:
            raise ValueError("Возраст должен быть от 0 до 150")
        return True

# Использование
try:
    SimpleValidator.validate_email("user@example.com")
    SimpleValidator.validate_age(25)
except (TypeError, ValueError) as e:
    print(f"Ошибка валидации: {e}")

2. Dataclasses + встроенная валидация

Для структурированных данных можно использовать dataclasses с post-init валидацией:

from dataclasses import dataclass
import re

@dataclass
class User:
    name: str
    email: str
    age: int
    
    def __post_init__(self):
        if not self.name or len(self.name) < 2:
            raise ValueError("Имя должно быть минимум 2 символа")
        
        email_pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
        if not re.match(email_pattern, self.email):
            raise ValueError("Некорректный email")
        
        if not (0 <= self.age <= 150):
            raise ValueError("Некорректный возраст")

# Использование
try:
    user = User(name="John", email="john@example.com", age=30)
except ValueError as e:
    print(f"Ошибка: {e}")

3. Pydantic (рекомендуется)

Мощная библиотека для валидации и сериализации данных. Используется в FastAPI, Django и других фреймворках.

from pydantic import BaseModel, Field, EmailStr, field_validator
from typing import Optional

class UserValidator(BaseModel):
    name: str = Field(..., min_length=2, max_length=100)
    email: EmailStr  # Автоматическая валидация email
    age: int = Field(..., ge=0, le=150)
    phone: Optional[str] = None
    
    @field_validator("name")
    @classmethod
    def name_must_be_alphabetic(cls, v):
        if not v.replace(" ", "").isalpha():
            raise ValueError("Имя должно содержать только буквы")
        return v.title()
    
    @field_validator("phone")
    @classmethod
    def validate_phone(cls, v):
        if v and len(v.replace("-", "")) != 10:
            raise ValueError("Номер должен содержать 10 цифр")
        return v

# Использование
try:
    user = UserValidator(
        name="john doe",
        email="john@example.com",
        age=30,
        phone="123-456-7890"
    )
    print(user.model_dump())
except ValueError as errors:
    print(f"Ошибки валидации: {errors}")

4. Marshmallow

Популярная библиотека для сериализации и десериализации данных:

from marshmallow import Schema, fields, ValidationError, validate, post_load

class UserSchema(Schema):
    name = fields.Str(
        required=True,
        validate=validate.Length(min=2, max=100)
    )
    email = fields.Email(required=True)
    age = fields.Int(
        required=True,
        validate=validate.Range(min=0, max=150)
    )
    
    @post_load
    def make_user(self, data, **kwargs):
        return {"status": "validated", **data}

# Использование
schema = UserSchema()
try:
    result = schema.load({
        "name": "John",
        "email": "john@example.com",
        "age": 30
    })
    print(result)
except ValidationError as err:
    print(f"Ошибки: {err.messages}")

5. Класс с дескрипторами (продвинутый подход)

Для более сложной логики валидации можно использовать дескрипторы:

class ValidatedProperty:
    def __init__(self, name, validator):
        self.name = name
        self.validator = validator
        self.private_name = f"_{name}"
    
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return getattr(obj, self.private_name, None)
    
    def __set__(self, obj, value):
        if not self.validator(value):
            raise ValueError(f"Некорректное значение для {self.name}")
        setattr(obj, self.private_name, value)

def is_valid_email(email):
    return isinstance(email, str) and "@" in email

def is_valid_age(age):
    return isinstance(age, int) and 0 <= age <= 150

class Person:
    email = ValidatedProperty("email", is_valid_email)
    age = ValidatedProperty("age", is_valid_age)
    
    def __init__(self, email, age):
        self.email = email
        self.age = age

# Использование
person = Person(email="john@example.com", age=30)
# person.age = 200  # Вызовет ValueError

6. Собственный декоратор для валидации функций

Для валидации аргументов функций:

from functools import wraps
from typing import Callable, Any

def validate_args(**validators):
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs):
            # Получаем параметры функции
            import inspect
            sig = inspect.signature(func)
            bound = sig.bind(*args, **kwargs)
            bound.apply_defaults()
            
            # Валидируем каждый аргумент
            for param_name, validator in validators.items():
                if param_name in bound.arguments:
                    value = bound.arguments[param_name]
                    if not validator(value):
                        raise ValueError(f"Некорректный аргумент {param_name}: {value}")
            
            return func(*args, **kwargs)
        return wrapper
    return decorator

@validate_args(
    email=lambda x: isinstance(x, str) and "@" in x,
    age=lambda x: isinstance(x, int) and 0 <= x <= 150
)
def register_user(email: str, age: int):
    return f"Пользователь {email} зарегистрирован"

# Использование
print(register_user("john@example.com", 30))
# register_user("invalid", 200)  # Вызовет ValueError

Сравнение подходов

ПодходСложностьПроизводительностьГибкостьРекомендуется
Try-exceptНизкаяВысокаяНизкаяПростые скрипты
DataclassesНизкаяВысокаяСредняяМалые проекты
PydanticСредняяСредняяВысокаяFastAPI, Django
MarshmallowСредняяСредняяВысокаяREST API
ДескрипторыВысокаяНизкаяОчень высокаяСложная логика
ДекораторыСредняяСредняяВысокаяФункции

Рекомендации для production

  • Используй Pydantic — это стандарт в Python экосистеме
  • Комбинируй валидацию — на уровне модели и бизнес-логики
  • Логируй ошибки валидации для отладки
  • Не доверяй пользовательским данным — валидируй всегда
  • Используй type hints для самодокументирования кода
Какие знаешь способы реализовать класс по проверки получаемых данных? | PrepBro