Как сделать объект правильно хешируемым?
Вот мой код:
class Hero:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return self.name + str(self.age)
def __hash__(self):
print(hash(str(self)))
return hash(str(self))
heroes = set()
heroes.add(Hero('Zina Portnova', 16)) # gets hash -8926039986155829407
print(len(heroes)) # gets 1
heroes.add(Hero('Lara Miheenko', 17)) # gets hash -2822451113328084695
print(len(heroes)) # gets 2
heroes.add(Hero('Zina Portnova', 16)) # gets hash -8926039986155829407
print(len(heroes)) # gets 3! WHY?
Почему это происходит?
1-й и 3-й объекты имеют одинаковый контент и один и тот же хэш, но len()
рассказывает о 3 уникальных объектах?
Ответы
Ответ 1
Вам также необходимо определить __eq__()
совместимым способом с __hash__()
- в противном случае равенство будет основано на идентификаторе объекта.
В Python 2 рекомендуется также определить __ne__
, чтобы сделать !=
совместимым с ==
. На Python 3 по умолчанию реализация __ne__
будет делегировать __eq__
для вас.
Ответ 2
Вот весь код:
class Hero:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return self.name + str(self.age)
def __hash__(self):
print(hash(str(self)))
return hash(str(self))
def __eq__(self,other):
return self.name == other.name and self.age== other.age
heroes = set()
heroes.add(Hero('Zina Portnova', 16)) # gets hash -8926039986155829407
print(len(heroes)) # gets 1
heroes.add(Hero('Lara Miheenko', 17)) # gets hash -2822451113328084695
print(len(heroes)) # gets 2
heroes.add(Hero('Zina Portnova', 16)) # gets hash -8926039986155829407
print(len(heroes)) # gets 2
Функция распознает __eq__
, и поэтому len равно 2.
Ответ 3
Документация Python может быть полезна:
Если класс не определяет метод __cmp__()
или __eq__()
, он не должен определять операцию __hash__()
: