Глава 14 · Создаём объекты реального мира

Специальные методы

__init__ — не единственный дандер-метод. __str__ и __eq__ подключают объект к print() и ==.

Как объекты подключаются к встроенным операциям

Когда вы пишете print(rex) или len(text) , Python на самом деле вызывает специальный метод объекта с именем вида __имя__ («дандер», double underscore). Вы уже пользовались одним таким методом с самого начала главы — __init__.

Что вы пишетеЧто Python вызывает на самом деле
Sobaka("Рекс", 3)__init__(self, ...)
print(rex)__str__(self)
len(korzina)__len__(self)
a + b__add__(self, other)
a == b__eq__(self, other)

__str__ и __repr__

Без специального метода print(объект) выводит малополезную строку вроде <__main__.Sobaka object at 0x7f...>. __str__ позволяет задать понятный человеку вид:

str_metod.py
class Sobaka:
    def __init__(self, klichka, vozrast):
        self.klichka = klichka
        self.vozrast = vozrast

    def __str__(self):
        return f"{self.klichka} ({self.vozrast} года)"

rex = Sobaka("Рекс", 3)
print(rex)   # Рекс (3 года) — а не адрес в памяти

__eq__: сравнение по значению, а не по идентичности

В разделе 14.9 a1 == a2 у двух Player с одинаковыми значениями оказалось False — потому что == по умолчанию сравнивает объекты как разные ячейки памяти. __eq__ это меняет:

eq_metod.py
class Sobaka:
    def __init__(self, klichka, vozrast):
        self.klichka = klichka
        self.vozrast = vozrast

    def __eq__(self, other):
        return self.klichka == other.klichka and self.vozrast == other.vozrast

Sobaka("Рекс", 3) == Sobaka("Рекс", 3)   # теперь True
Debug Lab 12: __eq__ определили, а объект стал unhashable
unhashable_obekt.py
class Tochka:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

tochki = {Tochka(1, 2), Tochka(3, 4)}   # положили объекты в множество
Traceback (most recent call last):
TypeError: unhashable type: 'Tochka'
Что видно на экране

У объекта по умолчанию есть автоматический __hash__, основанный на его адресе в памяти. Как только вы определяете свой __eq__, Python СНИМАЕТ автоматический __hash__ — ведь если объекты «равны» по значению, у равных объектов логично ожидать и одинаковый хеш, а старый адресный хеш этому больше не соответствует. Объект без хеша нельзя положить в set или использовать как ключ dict.

Исправленный код
s_hash.py
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __hash__(self):
        return hash((self.x, self.y))
Практика: специальные методы
Интерактивный ноутбук прямо в браузере — Python 3.14 через Pyodide, без установки
Открыть практику →