【问题标题】:How to make an unfrozen dataclass instance hashable?如何使解冻的数据类实例可散列?
【发布时间】:2019-04-17 20:47:38
【问题描述】:

当用frozen=False(默认行为)定义一个数据类,然后实例化这个类的一个对象时,有没有办法使这个对象可散列?

我为什么需要这个?

在 Python 3.7 之前,我使用命名元组而不是数据类,我曾经使用 set() 查找重复项,但我不能再使用它了。 出于其他原因,我不想在数据类上使用frozen=True。

【问题讨论】:

  • 什么“其他原因”?如果你想要哈希,你几乎总是想要冻结
  • @wim 因为在一种情况下,我需要数据类的可变性来修改属性,而在另一种情况下,我需要比较这些对象的 2 个列表之间的相等性。也许我可以编写 2 个具有相同属性的不同数据类,但一个冻结,另一个不冻结?
  • @DavidD.:听起来你可能对 dataclasses.replace 感兴趣。
  • 是的!我刚刚看到dataclasses.astuple 也可以做到这一点

标签: python python-dataclasses


【解决方案1】:

有一个参数:

@dataclass(unsafe_hash=True)
class Whatever:
    ...

不过,您可能应该使用frozen=True。如果需要更新冻结数据类实例的属性,可以使用dataclasses.replace 构造一个新对象:

new_thing = dataclasses.replace(old_thing, var=new_val)

当您需要可散列的东西时,您还可以使用可变数据类实例和dataclasses.astuple 来获取元组。不过要小心 - astuple 有一堆奇怪的复制行为,所以你可以得到如下行为:

In [1]: import dataclasses

In [2]: @dataclasses.dataclass
   ...: class Foo:
   ...:     a: object
   ...:     b: object
   ...:     

In [3]: x = object()

In [4]: a = Foo(x, x)

In [5]: b = dataclasses.astuple(a)

In [6]: b[0] is b[1]
Out[6]: False

In [7]: b[0] is x
Out[7]: False

In [8]: a == a
Out[8]: True

In [9]: dataclasses.astuple(a) == dataclasses.astuple(a)
Out[9]: False

【讨论】:

  • 谢谢,听起来很有趣。我读到“如果你的类在逻辑上是不可变的,但仍然可以改变。这是一个特殊的用例,应该仔细考虑。”你能详细说明一下这个“不安全”的特点吗?
  • @DavidD.:与任何其他可变、可散列对象不安全的原因相同:突变会破坏该对象可能位于的任何集合、字典或其他基于散列的数据结构。
  • 我就是这么想的。我可以要求您通过与其他解决方案(replace、astuple)的比较来完成您的答案,以便我可以将您的答案标记为已接受?再次感谢。
  • @DavidD.:答案已扩展。
猜你喜欢
  • 2019-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-28
  • 1970-01-01
  • 2012-11-02
  • 1970-01-01
相关资源
最近更新 更多