Как сделать так, чтобы класс данных Python наследовал __hash__? - PullRequest
0 голосов
/ 31 декабря 2018

Следующее будет работать, но я бы предпочел не повторять __hash__ в каждом подклассе.Есть ли способ сказать классу данных, что он наследует хеш-функцию (т.е. не устанавливает ее в None)?

from dataclasses import dataclass


@dataclass
class Hashable:

    def __hash__(self):
        hashed = hash((
            getattr(self, key)
            for key in self.__annotations__
            ))
        return hashed


@dataclass
class Node(Hashable):
    name: str = 'Undefined'

    def __hash__(self):
        return Hashable.__hash__(self)

1 Ответ

0 голосов
/ 31 декабря 2018

Причина вашего __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

...