Ответ
При использовании объекта пользовательского класса в качестве ключа словаря Python задействует два dunder-метода: __hash__ и __eq__.
Процесс работы:
__hash__(self): Сначала вызывается этот метод для вычисления хэша объекта. Хэш — это целое число, которое используется для быстрого определения «корзины» (bucket) в хэш-таблице словаря, где должен храниться элемент. Это позволяет находить элементы за время, близкое к O(1).__eq__(self, other): Вызывается только в случае коллизии хэшей — когда у двух разных объектов оказывается одинаковый хэш. Этот метод выполняет точную проверку на равенство, чтобы определить, является ли ключ тем же самым.
Ключевое правило: Объекты, которые равны (согласно __eq__), должны иметь одинаковый хэш (согласно __hash__). Обратное неверно: объекты с одинаковым хэшем не обязательно равны.
Пример:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 1. Метод для проверки на равенство
def __eq__(self, other):
if not isinstance(other, Person):
return NotImplemented
return self.name == other.name and self.age == other.age
# 2. Метод для вычисления хэша
# Хэш должен быть одинаковым для равных объектов
def __hash__(self):
return hash((self.name, self.age))
p1 = Person("Alice", 30)
p2 = Person("Alice", 30) # p1 == p2, и hash(p1) == hash(p2)
data = {p1: "some_value"}
# Поиск происходит по p2, но находится значение для p1
print(data[p2]) # Вывод: some_value
Важное замечание:
- Неизменяемость (Immutability): Ключи словаря должны быть неизменяемыми. Если хэш объекта изменится после добавления в словарь, его невозможно будет найти.
- Согласованность: Если вы переопределяете
__eq__, вы обязаны переопределить и__hash__. В противном случае объект станет "unhashable" и вызоветTypeErrorпри попытке использовать его в качестве ключа.