Подтвердить что ты не робот

Как сделать объект правильно хешируемым?

Вот мой код:

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 уникальных объектах?

4b9b3361

Ответ 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__():