【问题标题】:How do I make a python dataclass inherit __hash__?如何让 python 数据类继承 __hash__?
【发布时间】:2018-12-31 18:14:34
【问题描述】:

以下将起作用,但我宁愿不需要在每个子类中重复 __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)

【问题讨论】:

  • 您想自己定义该哈希有什么特别的原因吗?如果你设置frozen=True,它基本上是一个错误的、不太安全的版本。

标签: python hash data-class


【解决方案1】:

您的__hash__ 设置为None 原因dataclasses 试图阻止您在脚下射击自己。您的第二个类有 eq=True 用于数据类装饰器(这是默认值)。来自文档:

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

如果 eq 和 freeze 都为真,默认情况下 dataclass() 将生成一个 __hash__() 适合您的方法。 如果 eq 为真,frozen 为假,__hash__() 将设置为 None,将其标记为不可散列(因为它是可变的)。 如果 eq 为假,__hash__() 将被保留 untouched 意味着将使用超类的__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

但是,正如 cmets 中指出的那样,这不是很安全,因为您有一个可变对象现在可以进行哈希处理,并且与它的 __eq__ 的实现不一致,它继承自 @987654335 @

【讨论】:

  • 我想说真正的问题是他们完全定义了这个__hash__,而不是使用frozen=True
  • @user2357112 我同意
  • @user2357112 这个例子一定很简单。假设frozen 对我的用例来说甚至是一个好主意,这是一个糟糕的假设。
  • @BrianBruggeman:嗯,你的例子 __hash__ 有问题(错误地处理 ClassVarInitVar 和继承的字段),如果你特别不想要 frozen=True,那么它听起来你想要可变的可哈希对象,这通常是个坏主意。即使您不想要frozen=Trueunsafe_hash=True 也可能是一个更好的主意。
  • Unsafe 实际上只处理简单的原语,不会处理更复杂的情况。我想要一个可重用的函数,我既可以测试又可以传递一系列子类。拥有 dataclass(eq=False) 实际上比我原来的例子更令人困惑/不太清楚。
猜你喜欢
  • 1970-01-01
  • 2022-12-03
  • 1970-01-01
  • 1970-01-01
  • 2018-03-10
  • 2021-04-10
  • 2019-01-05
相关资源
最近更新 更多