14

以下将起作用,但我宁愿不需要__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)
4

1 回答 1

10

你被设置的原因是试图阻止你在脚上射击自己。您的第二个类具有数据类装饰器(这是默认值)。从文档:__hash__Nonedataclasseseq=True

以下是管理方法隐式创建的规则__hash__()。请注意,您不能__hash__()在数据类中同时使用显式方法并设置 unsafe_hash=True; 这将导致一个TypeError.

如果 eq 和 freeze 都为真,默认情况下 dataclass() 将为 __hash__()您生成一个方法。如果 eq 为真,frozen 为假,__hash__() 将被设置为 None,将其标记为不可散列(它是,因为它是可变的)。如果 eq 为假,__hash__()将保持不变,这意味着__hash__()将使用超类的方法(如果超类是object,这意味着它将回退到基于 id 的散列)。

所以只需通过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

于 2018-12-31T18:38:54.840 回答