← Все вопросы

Почему после переопределения __eq__ объект перестал работать как ключ словаря?

Задан 14 месяцев назад389 просмотров3 ответа
12

Сделал сравнение по значению через __eq__, всё хорошо. Но теперь:

d = {}
d[Point(1, 2)] = 'a'
# TypeError: unhashable type: 'Point'

До этого работало. Что случилось?

3 ответа

19
✓ Принятый ответ — помог автору

Когда ты определяешь свой __eq__, Python автоматически выставляет __hash__ = None, и объект становится нехешируемым. Логика такая: если два объекта равны, у них обязан совпадать хеш, иначе словари и множества будут работать неправильно. Питон не может угадать твой хеш сам, поэтому отключает его, чтобы ты не наступил на баг.

Решение — определить __hash__ явно, обычно по тому же набору полей, что и в __eq__:

def __hash__(self):
    return hash((self.x, self.y))

Но это безопасно только если объект неизменяемый. Если ты будешь менять x/y после того как положил объект в set, он потеряется. Поэтому хешируемыми делают только immutable-объекты.

Евгений Казбан Вот это "равны → хеши равны" — золотое правило, нарушишь и получишь невидимые баги · 14 месяцев назад
6

Питон занулил __hash__, когда ты добавил __eq__. Допиши свой __hash__ по тем же полям.

4

Сделай класс через @dataclass(frozen=True) — он сам сгенерит и __eq__, и __hash__.

Ваш ответ

Войдите, чтобы ответить на вопрос.
Поддержать проект