В последнее время я обнаружил интересное наблюдение, что есть вещи, которые влияют на хеш-свойство объекта / экземпляра класса. И мне интересно как и почему?
Например, я получил класс связанного списка с именем ListNode
:
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def __repr__(self):
if self.next:
return "{}->{}".format(self.val, repr(self.next))
else:
return "{}".format(self.val)
# def __eq__(self, other):
# if not self and not other:
# return True
# elif not self or not other:
# return False
# else:
# return self.val == other.val and self.next == other.next
# def __eq__(self, other):
# return str(self) == str(other)
Обратите внимание, что я заблокировал метод __eq__
.
Теперь, если я создам экземпляр:
A = ListNode(1)
B = ListNode(2)
C = ListNode(3)
A.next = B
B.next = C
print(hash(A))
Тогда он может быть хэшируемым, однако я получаю разные выходные значения при каждом запуске.
Теперь, если я разблокирую метод __eq__
, внезапно он больше не будет хэшируемым. Зачем?
Похоже, что метод hash
будет использовать __eq__
. И как он узнает, что он не может быть хешируемым после включения __eq__
?
Дополнительно:
Если я напишу метод __eq__
для сравнения версии связанного списка str
(второй метод __eq__
), я подумал, что это может решить проблему, потому что путем преобразования связанного списка в string
, данные становятся хешируемыми, но я все равно получаю сообщение об ошибке unhashable
1027 *
Спасибо!
Согласно комментарию @ juanpa.arrivillaga:
__eq__
удалит метод __hash__
по умолчанию, что сделает его недоступным для использования.
Поэтому я добавил свой собственный __hash__
метод:
def __hash__(self):
return hash(id(self))
Это решило проблему и снова сделало ListNode
хешируемым с включенным __eq__
.