Почему после переопределения __eq__ объект перестал работать как ключ словаря?
Сделал сравнение по значению через __eq__, всё хорошо. Но теперь:
d = {}
d[Point(1, 2)] = 'a'
# TypeError: unhashable type: 'Point'
До этого работало. Что случилось?
3 ответа
Когда ты определяешь свой __eq__, Python автоматически выставляет __hash__ = None, и объект становится нехешируемым. Логика такая: если два объекта равны, у них обязан совпадать хеш, иначе словари и множества будут работать неправильно. Питон не может угадать твой хеш сам, поэтому отключает его, чтобы ты не наступил на баг.
Решение — определить __hash__ явно, обычно по тому же набору полей, что и в __eq__:
def __hash__(self):
return hash((self.x, self.y))
Но это безопасно только если объект неизменяемый. Если ты будешь менять x/y после того как положил объект в set, он потеряется. Поэтому хешируемыми делают только immutable-объекты.
Питон занулил __hash__, когда ты добавил __eq__. Допиши свой __hash__ по тем же полям.
Сделай класс через @dataclass(frozen=True) — он сам сгенерит и __eq__, и __hash__.