📜 Как показано в исходном материале
Исходные примеры корректны, но не содержат аннотаций типов и не всегда защищают методы сравнения через isinstance:
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
def __repr__(self):
return f"Book(title={self.title})"
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
if not isinstance(other, Vector):
return NotImplemented
return Vector(self.x + other.x, self.y + other.y)
def __str__(self):
return f"({self.x}, {self.y})"
Что здесь происходит: логика верная, но без подсказок типов читателю приходится догадываться, какие аргументы принимает метод и что возвращает.
❌ Почему этот подход можно улучшить
- Нет аннотаций типов. Неясно, что
title— строка, аx,y— числа. - Меньше защиты. В
__lt__нет проверки типаother; при сравнении с неожиданным типом может возникнуть непонятная ошибка. - Нет guard clauses. В некоторых исходных примерах используются лишние
elseпослеreturn. - Нет современных инструментов. Например,
dataclassesмогли бы убрать шаблонный__init__и__repr__.
✅ Рекомендуемый современный вариант
Та же логика, но с type hints, f-strings, защитой типов и dataclasses:
from __future__ import annotations
from dataclasses import dataclass
from functools import total_ordering
@total_ordering
@dataclass
class Book:
title: str
def __eq__(self, other: object) -> bool:
if not isinstance(other, Book):
return NotImplemented
return self.title == other.title
def __lt__(self, other: Book) -> bool:
if not isinstance(other, Book):
return NotImplemented
return self.title < other.title
class Vector:
def __init__(self, x: float, y: float) -> None:
self.x = x
self.y = y
def __add__(self, other: Vector) -> Vector:
if not isinstance(other, Vector):
return NotImplemented
return Vector(self.x + other.x, self.y + other.y)
def __repr__(self) -> str:
return f"Vector({self.x}, {self.y})"
- Аннотации типов сразу показывают контракт метода.
- Проверка
isinstanceво всех методах защищает от неожиданных типов. dataclassубирает boilerplate для__init__и__repr__.@total_orderingсокращает код сравнений.
🕰️ Когда старый подход ещё можно встретить
Код без type hints и с ручным __init__ часто встречается в учебных материалах, тестовых скриптах и legacy-проектах, написанных до Python 3.6. Если вы видите такой код, не спешите всё переписывать: сначала убедитесь, что логика корректна, а затем постепенно добавляйте типизацию и тесты.