Сравните два подхода и выбирайте более ясный и безопасный вариант, сохраняя старый синтаксис только для чтения существующего кода.
Абстрактный класс vs обычный класс
Критерий
Обычный класс
Абстрактный класс
Создание объектов
Разрешено
Запрещено
Назначение
Готовая реализация
Интерфейс + общая логика
Контроль наследников
Не гарантирует переопределение
Обязывает реализовать методы
# Обычный класс — можно создать, даже если метод пуст
class Worker:
def work(self): pass
w = Worker() # OK
# Абстрактный класс — защита от незавершённых объектов
from abc import ABC, abstractmethod
class Worker(ABC):
@abstractmethod
def work(self): pass
# w = Worker() # TypeError
Встроенные vs пользовательские исключения
Подход
Плюсы
Минусы
Встроенные (ValueError и др.)
Не нужно ничего создавать
Не передаёт специфику домена
Пользовательские от Exception
Ясно отделяет ошибки логики
Больше кода
Пользовательские от подкласса (ValueError)
Точность + совместимость
Нужно выбрать правильного родителя
Ручные методы vs магические методы
Подход
Синтаксис
Когда использовать
Обычные методы
a.equals(b)
Когда нужен явный вызов метода
Магические методы
a == b, len(a)
Когда объект ведёт себя как встроенный тип
# Вручную
if book1.equals(book2):
print("Равны")
# Через dunder
if book1 == book2:
print("Равны")
Все сравнения vs @total_ordering
Подход
Количество методов
Риск ошибки
Ручная реализация всех методов
6
Высокий (противоречивые правила)
@total_ordering
2 (__eq__ + один)
Низкий, Python генерирует остальное
from functools import total_ordering
@total_ordering
class Person:
def __eq__(self, other):
...
def __lt__(self, other):
...
# Остальные операторы работают автоматически