Причина вашего __hash__
установлена на None
в том, что dataclasses
пытается помешать вам выстрелить себе в ногу.Ваш второй класс имеет eq=True
для декоратора класса данных (это значение по умолчанию).Из документов:
Вот правила, управляющие неявным созданием метода __hash__()
.Обратите внимание, что вы не можете одновременно иметь явный метод __hash__()
в своем классе данных и установить unsafe_hash = True;это приведет к TypeError
.
Если eq и frozen оба имеют значение true, по умолчанию dataclass () сгенерирует метод __hash__()
для вас. Если eq равно true, а замораживается как false, __hash __ () будет установлен в значение None, помечая его как не подлежащее обработке (что является изменяемым). Если eq равно false, __hash__()
останется нетронутымэто означает, что будет использован метод __hash__()
суперкласса (если суперкласс object
, это означает, что он вернется к хешированию на основе идентификаторов).
Так что просто передайте eq=False
:
In [1]: from dataclasses import dataclass
...:
...:
...: @dataclass
...: class Hashable:
...:
...: def __hash__(self):
...: hashed = hash((
...: getattr(self, key)
...: for key in self.__annotations__
...: ))
...: return hashed
...:
...:
...: @dataclass(eq=False)
...: class Node(Hashable):
...: name: str = 'Undefined'
...:
In [2]: hash(Node())
Out[2]: -9223372036579626267
Однако, как указано в комментариях, это не очень безопасно, поскольку у вас есть изменяемый объект, который теперь можно хешировать, и это несовместимо с его реализацией __eq__
, котораянаследуется от Hashable