Магические методы: __str__, __repr__, __eq__
Магические методы: str, repr, eq
Python использует специальные методы с двойными подчёркиваниями (__name__) для интеграции объектов со встроенными операциями языка. Их называют магическими методами или dunder-методами (от double underscore). Определив их в классе, вы учите Python, как работать с вашими объектами.
str: читаемое строковое представление
Когда вы вызываете print(obj) или str(obj), Python ищет метод __str__. Если его нет — выводится что-то вроде <__main__.Dog object at 0x7f...>. Бесполезно для отладки:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"Point({self.x}, {self.y})"
p = Point(3, 4)
print(p) # Point(3, 4)
print(str(p)) # Point(3, 4)
print(f"Точка: {p}") # Точка: Point(3, 4)
__str__ возвращает строку, понятную пользователю.
repr: техническое представление
__repr__ (representation) — техническое описание, полезное для разработчика. Вызывается в REPL и через repr(). Соглашение: строка, которую можно скопировать и выполнить, чтобы воссоздать объект:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point({self.x!r}, {self.y!r})"
def __str__(self):
return f"({self.x}, {self.y})"
p = Point(3, 4)
print(repr(p)) # Point(3, 4) — техническое
print(str(p)) # (3, 4) — пользовательское
lst = [Point(1, 2), Point(3, 4)]
print(lst) # [Point(1, 2), Point(3, 4)] — в контейнерах Python использует __repr__
Если __str__ не определён, Python использует __repr__ везде. Если нужен только один — определяйте __repr__.
eq: сравнение объектов
По умолчанию == сравнивает объекты по идентичности (is): два разных объекта с одинаковыми данными не равны:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p1 = Point(3, 4)
p2 = Point(3, 4)
print(p1 == p2) # False — разные объекты в памяти
Определив __eq__, вы задаёте логику сравнения:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
if not isinstance(other, Point):
return NotImplemented
return self.x == other.x and self.y == other.y
p1 = Point(3, 4)
p2 = Point(3, 4)
p3 = Point(1, 2)
print(p1 == p2) # True
print(p1 == p3) # False
print(p1 == "не точка") # False (NotImplemented → Python пробует обратное)
NotImplemented (не NotImplementedError) — специальное значение, говорящее Python: «я не умею сравнивать с этим типом, попробуй другую сторону».
Другие полезные dunder-методы
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other): # v1 + v2
return Vector(self.x + other.x, self.y + other.y)
def __len__(self): # len(v)
return 2 # вектор двумерный
def __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
print(len(v1)) # 2
Таблица популярных dunder-методов:
| Метод | Когда вызывается |
|---|---|
__str__ | str(obj), print(obj), f-строки |
__repr__ | repr(obj), REPL, контейнеры |
__eq__ | obj == other |
__len__ | len(obj) |
__add__ | obj + other |
__lt__ | obj < other |
__contains__ | x in obj |
Итог
__str__— читаемое строковое представление для пользователя.__repr__— техническое представление для разработчика; используется в REPL и контейнерах.__eq__— логика сравнения через==; возвращайтеNotImplementedдля неподдерживаемых типов.- Dunder-методы интегрируют объекты с операторами и встроенными функциями Python.
В следующем уроке разберём инкапсуляцию и приватные атрибуты — как защитить данные объекта от нежелательного изменения снаружи.