📖 Теория: повторение уроков 76–78

⚡ Кратко

Абстрактные классы из abc.ABC с @abstractmethod задают обязательный интерфейс. Docstrings описывают классы и доступны через __doc__. Пользовательские исключения наследуются от Exception и могут хранить дополнительные данные. Магические методы позволяют объектам работать с операторами сравнения, индексации, арифметики, len(), bool() и вызова.

1. Абстрактные классы

Абстрактный класс — это класс, который нельзя использовать для создания объектов напрямую. Он служит шаблоном и задаёт методы, обязательные для реализации в дочерних классах.

from abc import ABC, abstractmethod

class Employee(ABC):
    @abstractmethod
    def work(self):
        pass

class Programmer(Employee):
    def work(self):
        print("Write code")

p = Programmer()
p.work()
  • Класс должен наследоваться от ABC.
  • Абстрактные методы помечаются декоратором @abstractmethod.
  • Можно совмещать абстрактные и обычные (реализованные) методы.
  • Попытка создать Employee() вызовет TypeError.
Обычный классАбстрактный класс
Можно создавать объектыСоздание объектов запрещено
Переопределение методов не обязательноНекоторые методы обязательны к реализации
Используется напрямуюИспользуется как основа для наследования

2. Документация классов

Docstring пишется сразу под объявлением класса в тройных кавычках. Он описывает назначение класса, атрибуты и методы.

class Book:
    """
    Represents a book.

    Attributes:
        title (str): The title of the book.
        author (str): The author of the book.

    Methods:
        get_info(): Returns a brief description of the book.
    """
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def get_info(self):
        return f"{self.title} by {self.author}"

print(Book.__doc__)

Рекомендации: перечисляйте атрибуты и методы, кратко описывайте назначение, используйте единый стиль по проекту.

3. Пользовательские исключения

Пользовательские исключения позволяют точно указать причину ошибки и отделить ошибки собственной логики от встроенных.

class AccessDeniedError(Exception):
    """Вызывается, если пользователь слишком молод для доступа."""
    pass

def check_age(age):
    if age < 18:
        raise AccessDeniedError("Access denied: age must be at least 18")
    print("Access granted")

try:
    check_age(16)
except AccessDeniedError as e:
    print("Ошибка:", e)
  • Наследуются от Exception или его подклассов, а не от BaseException.
  • Имена принято заканчивать на Error.
  • Могут быть пустыми (pass) или содержать собственную логику.

Дополнительные поля в исключениях

Дополнительные поля помогают передавать в обработчик контекст ошибки:

class AccessDeniedError(Exception):
    def __init__(self, age):
        self.age = age
        super().__init__(f"Access denied: age {age} is too low")

try:
    raise AccessDeniedError(15)
except AccessDeniedError as e:
    print("Error:", e)
    print("Age:", e.age)

Если исключение относится к конкретному типу ошибки, лучше наследоваться от подходящего встроенного исключения, например ValueError:

class TemperatureTooLowError(ValueError):
    pass

4. Магические методы

Магические (dunder) методы управляют поведением объектов во встроенных ситуациях: при сравнении, арифметике, итерации, преобразовании в строку и т.д.

ВыражениеМетодНазначение
str(obj)__str__Строковое представление
len(obj)__len__Количество элементов
obj1 == obj2__eq__Равенство
obj1 + obj2__add__Сложение
item in obj__contains__Проверка вхождения
obj()__call__Объект как функция
bool(obj)__bool__Логическое значение

5. Методы сравнения и @total_ordering

МетодОператор
__eq__==
__ne__!=
__lt__<
__le__<=
__gt__>
__ge__>=

Достаточно реализовать __eq__ и один из методов сравнения, чтобы сортировка и операторы работали. Декоратор @total_ordering из functools автоматически построит остальные сравнения.

from functools import total_ordering

@total_ordering
class Book:
    def __init__(self, title):
        self.title = title

    def __eq__(self, other):
        if not isinstance(other, Book):
            return NotImplemented
        return self.title == other.title

    def __lt__(self, other):
        return self.title < other.title

Всегда проверяйте тип other через isinstance и возвращайте NotImplemented, если сравнение невозможно.

6. Индексация и доступ к элементам

МетодНазначениеИспользование
__getitem__Получить элемент по ключу/индексуvalue = obj[key]
__setitem__Установить значение по ключуobj[key] = value
__contains__Проверить наличие элементаkey in obj
__len__Вернуть количество элементовlen(obj)

Эти методы позволяют создавать объекты, похожие на словари и списки.

7. Арифметические методы

МетодОператор
__add__+
__sub__-
__mul__*
__truediv__/
__floordiv__//
__mod__%
__pow__**

Для изменения объекта на месте используются инкрементные методы: __iadd__, __isub__, __imul__ и т.д. Они должны изменять self и возвращать его.

__bool__ и __call__

__bool__ определяет поведение объекта в логических выражениях. Если метод не определён, Python использует __len__ (пустой объект — ложный).

__call__ позволяет обращаться к объекту как к функции: obj(...). Это удобно для конвертеров, счётчиков и декораторов.