Как связаны __eq__ и __hash__ и что значит «хешируемый объект»?
- Почему список нельзя положить в set или сделать ключом словаря?
- Что будет, если переопределить __eq__ без __hash__?
Хешируемый объект имеет хеш, неизменный за всё время жизни, и сравнивается через __eq__. Правило: равные объекты обязаны иметь равные хеши. Если класс переопределяет __eq__ без __hash__, Python ставит __hash__ = None — экземпляры становятся нехешируемыми.
- list, dict, set изменяемы и нехешируемы; tuple — хешируем, если хешируемы элементы
- Хеш считают по тем же неизменяемым полям, что и равенство: hash((self.x, self.y))
- @dataclass(frozen=True) генерирует согласованную пару
А ещё Хеш строк рандомизируется между запусками (PYTHONHASHSEED) — защита от атак на словари
Подробно
Как словарь ищет ключ: вычисляет hash(key), по нему находит ячейку, а при совпадении хешей сравнивает через ==. Если равные объекты дают разные хеши, словарь их не найдёт.
Почему изменяемые нехешируемы. Если бы список был ключом и потом изменился, его хеш изменился бы — запись осталась бы в ячейке старого хеша и стала недоступной.
class Point:
def __init__(self, x, y): self.x, self.y = x, y
def __eq__(self, other):
return isinstance(other, Point) and (self.x, self.y) == (other.x, other.y)
def __hash__(self):
return hash((self.x, self.y))
По умолчанию объекты сравниваются по идентичности и хешируются по id — это согласовано. Переопределили __eq__ — Python обнулил __hash__, чтобы не допустить несогласованности; нужно определить его явно.
Возвращать NotImplemented из __eq__ для чужих типов — тогда Python попробует сравнение с другой стороны.
Что хотят услышать
- Определение хешируемости и правило.
- Поведение при переопределении только __eq__.
- Почему изменяемые объекты нехешируемы.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Хеш стоит считать по изменяемым полям: так он отражает текущее состояние объекта и в словаре, и в set
- ✓Равные объекты обязаны иметь равные хеши; __eq__ без __hash__ делает объект нехешируемым
- ✗Равные объекты могут иметь разные хеши, а одинаковый хеш гарантирует, что объекты равны
- ✗list хешируем, если все его элементы хешируемы, — точно так же, как кортеж из тех же элементов
Разбор темы
- Модель данных — создание объектов, атрибуты и дескрипторы
__new__ и __init__, согласование __eq__ и __hash__, __getattr__ и __getattribute__, дескрипторы и __slots__.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.