class MyClass:
    def __init__(self, value):
        if not isinstance(value, int):
            raise TypeError("Value must be an integer")
        if value < 0:
            raise ValueError("Value must be non-negative")
        self.value = value
  При обработке ошибок в конструкторе класса Python, когда переданы некорректные данные, важно обеспечить, чтобы объект не создавался в некорректном состоянии и чтобы вызывающий код был проинформирован об ошибке. Вот несколько подходов, которые можно использовать:
Это наиболее распространенный и рекомендуемый подход. В конструкторе проверяются переданные аргументы на соответствие ожидаемым типам, диапазонам и другим условиям. Если данные невалидны, возбуждается исключение, такое как ValueError, TypeError, или пользовательское исключение, которое отражает конкретную проблему.  Это предотвращает создание объекта в невалидном состоянии.
class MyClass:
    def __init__(self, value):
      if not isinstance(value, int):
        raise TypeError("Value must be an integer")
      if value < 0:
        raise ValueError("Value must be non-negative")
      self.value = value
    # ... остальной код класса
Хотя основная валидация происходит в конструкторе, для атрибутов, которые могут быть изменены после создания объекта, можно использовать свойства с методами setter, чтобы обеспечить валидацию при присвоении нового значения.
class MyClass:
    def __init__(self, value):
      self.value = value # Начальное присвоение через property (если требуется валидация)
    @property
    def value(self):
      return self._value
    @value.setter
    def value(self, new_value):
      if not isinstance(new_value, int):
        raise TypeError("Value must be an integer")
      if new_value < 0:
        raise ValueError("Value must be non-negative")
      self._value = new_value
dataclasses с аннотациями типов и валидацией:
      Для более структурированного подхода, особенно при работе с классами данных, можно использовать библиотеку dataclasses в сочетании с библиотеками валидации данных, например, pydantic или marshmallow. Это позволяет декларативно определить типы данных и правила валидации, которые будут автоматически применяться при создании объекта.
from dataclasses import dataclass
from typing import Type
from pydantic import BaseModel, ValidationError
class MyDataModel(BaseModel):
    value: int
    @validator("value")
    def value_must_be_positive(cls, value):
        if value < 0:
            raise ValueError("Value must be non-negative")
        return value
@dataclass
class MyClass:
    data: MyDataModel
    def __post_init__(self):
        try:
            self.data = MyDataModel(**self.data) # Преобразование dict в MyDataModel с валидацией
        except ValidationError as e:
            raise ValueError(f"Invalid data provided: {e}")
# Пример использования:
try:
    obj = MyClass(data={"value": -5})
except ValueError as e:
    print(f"Error creating object: {e}")
Вместо непосредственного вызова конструктора, можно использовать фабричную функцию или метод класса, который выполняет предварительную валидацию данных и возвращает либо экземпляр класса, либо None (или возбуждает исключение) в случае ошибки. Это позволяет отделить процесс валидации от процесса создания объекта.
class MyClass:
    def __init__(self, value):
        self.value = value
    @classmethod
    def create(cls, value):
        if not isinstance(value, int):
            raise TypeError("Value must be an integer")
        if value < 0:
            raise ValueError("Value must be non-negative")
        return cls(value)
try:
    obj = MyClass.create(-5)
except ValueError as e:
    print(f"Error creating object: {e}")
Рекомендации:
TypeError для неверного типа данных, ValueError для недопустимого значения).