Специальные методы
__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__ позволяет задать понятный человеку вид:
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__ это меняет:
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
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.
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __hash__(self):
return hash((self.x, self.y))