【问题标题】:Creating multiple separate instances of a dataclass with the same arguments创建具有相同参数的数据类的多个单独实例
【发布时间】:2021-09-24 19:01:14
【问题描述】:

我有一个简单的 Python 类,看起来像这样:

class RegularVariable:
    def __init__(self, num_states):
        self.num_states = num_states

我最近发现了 dataclasses 模块并将我的简单类替换为如下数据类:

@dataclass(frozen=True)
class DataClassVariable:
    num_states: int

(设置frozen=True 是因为我确实希望该类是只读的。)

现在,在我的代码中,我需要使用完全相同的num_states 创建一堆此类的实例。我可以使用旧的、简单的 RegularVariable 类轻松地做到这一点:

print(len(set([RegularVariable(1) for _ in range(10)])))
# prints 10 as expected

但是,当我用我的 dataclass 版本尝试同样的事情时:

print(len(set([DataClassVariable(1) for _ in range(10)])))
# prints 1

为什么dataclass 会这样?鉴于此,我怎样才能为我的DataClassVariable 创建 10 个不同的对象(实例化)?

【问题讨论】:

  • 我听说数据类默认不实现任何唯一的哈希,所以如果你没有实现一种方法来区分每个实例,因为你对所有实例都使用相同的值,set 可能实际上认为也许都是同一个例子。如果我错了,请纠正我,我会删除它;-)
  • DataClassVariable 的每个实例都具有相同的哈希值(我认为,仅基于其 num_states 属性的值),因此您的集合确实只有一个 DataClassVariable 实例它。
  • @DevLounge:如果你指定frozen=True,数据类默认实现__hash____eq__。这就是发生这种情况的原因 - 否则,您会收到10
  • 好吧,我说的不是太远,但也不对 ;-)
  • 没有选项可以简单地说“不要覆盖继承的__hash__ 函数”,这似乎很奇怪。

标签: python python-3.7 python-dataclasses


【解决方案1】:

基于cmets,解决方法是添加eq=False

@dataclass(frozen=True, eq=False)
class DataClassVariable:
    num_states: int

【讨论】:

  • 谢谢!我之前查看了文档,但现在我重新阅读它,它清楚地提到“这个方法比较类,就好像它是它的字段的元组,按顺序”,这是我想要禁用的行为。虽然这可以满足我的需求,但我从@chepner 的回答中意识到,这会产生额外的不良后果......
  • 没问题,我可能最终会删除这个答案,因为他确实更安全。但是该选项存在并且可能对某些人的要求有好处,所以不知道该怎么做。
  • 我认为它提供了丰富的信息,所以我会留下它;了解 imo 很有用。
  • 足够公平,所以我会离开它。
  • 是的,我也会保留它(尽管可能强调__hash__ 未生成是__eq__ 也未生成的结果)。
【解决方案2】:

frozen=True 时,dataclass 将尝试生成__hash__ 函数,并且将仅基于num_states 的值。

您可以将__hash__ 明确定义为类似

@dataclass(frozen=True)
class DataClassVariable:
    num_states: int
    def __hash__(self):
        return super().__hash__()

防止自动生成的函数使每个实例看起来相同。请注意,这不需要禁用 __eq__ 的自动生成。

【讨论】:

  • 哦,我的解决方案有问题吗?如果是,对不起
  • 没有错;它只是有额外的后果。我以为有办法专门避免生成__hash__,允许object.__hash__被继承,但似乎没有办法。
  • 是的,我先尝试了 If unsafe_hash=True,但仍然是 1 而不是 10,所以我尝试了 eq=False
  • unsafe_hash 显然强制dataclass 生成__hash__,即使dataclass 确定这样做不安全。我也尝试了num_states: int = fields(hash=False),但随后__hash__仍然生成,而不是让__hash__被继承。
  • 这使得__eq____hash__ 彼此不一致。
猜你喜欢
  • 2018-11-09
  • 1970-01-01
  • 2018-09-15
  • 1970-01-01
  • 2014-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多