【问题标题】:Python dataclass generate hash and exclude unsafe fieldsPython 数据类生成哈希并排除不安全字段
【发布时间】:2020-06-18 07:54:16
【问题描述】:

我有这个数据类:

from dataclasses import dataclass, field
from typing import List

@dataclass
class Person:
    name: str
    dob: str
    friends: List['Person'] = field(default_factory=list, init=False)

namedob 是不可变的,friends 是可变的。我想生成每个人对象的哈希。我可以以某种方式指定要包含和排除哪个字段以生成__hash__ 方法吗?在这种情况下,namedob 应该包含在生成哈希中,而 friends 不应该。这是我的尝试,但它不起作用

@dataclass
class Person:
    name: str = field(hash=True)
    dob: str = field(hash=True)
    friends: List['Person'] = field(default_factory=list, init=False, hash=False)
>>> hash(Person("Mike", "01/01/1900"))
Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
    hash(Person("Mike", "01/01/1900"))
TypeError: unhashable type: 'Person'

我也找不到将namedob 设置为冻结的方法。而且我会避免将unsafe_hash 设置为True,只是通过它的声音。有什么建议吗?

另外,我正在做的事情被认为是好的做法吗?如果没有,您能提出一些替代方案吗?

谢谢

编辑:这只是一个玩具示例,我们可以假设 name 和 dob 字段是唯一的。

编辑:我举了一个例子来说明错误。

【问题讨论】:

  • 听起来这些对象根本不应该是可散列的。
  • 好吧,如果你删除朋友,那么他们应该是可散列的,这就是我要问的。如何从哈希中排除朋友?我应该吗?
  • 假设我有我的朋友迈克,生于 1972 年 3 月 3 日,我的朋友其他迈克,巧合地也出生于 1972 年 3 月 3 日。说这两个人是平等的?如果不是,这个提议的哈希有什么好处?
  • 真的,生成__eq____hash__ 可能没有意义。您可以将eq=False 传递给dataclass 装饰器以避免生成任一方法,并让该类从object 继承默认的基于身份的__eq____hash__
  • 这听起来还是应该从object 继承__hash____eq__

标签: python python-dataclasses


【解决方案1】:

只需指出在将实例与__eq__ 进行比较时不应考虑friends 字段,并将hash=True 传递给所需字段上的字段实例。

然后,将 unsafe_hash=True 参数传递给 dataclass 装饰器本身 - 它会按您的意愿工作(大部分情况下):

在哈希的情况下,语言限制是如果一个实例与另一个实例比较相等(__eq__),则两者的哈希也必须相等。这种情况下的含义是,如果您有两个具有相同“name”和“dob”字段的“同一”人实例,即使它们具有不同的朋友列表,它们也将被视为相等。

除此之外,这应该可以:


from dataclasses import dataclass, field
from typing import List

@dataclass(unsafe_hash=True)
class Person:
    name: str = field(hash=True)
    dob: str = field(hash=True)
    friends: List['Person'] = field(default_factory=list, init=False, compare=False, hash=False)

然后,记住要表现得像一个“同意的成年人”,不要在任何地方更改 Person 实例的“name”和“dob”字段,然后就可以了。

【讨论】:

  • 为什么要这样做而不只是使用field(hash=False)
  • 因为我小心翼翼地在交互模式下尝试了这个,而 hash=False 没有用 - 而且,我还没有尝试过 unsafe_hash=True - 这应该可以 - 我会检查并更新.
  • "如果一个实例的哈希值与另一个实例的哈希值相同,则两者也应该与 eq 比较相等"我认为您倒过来了。规则是:如果两个对象比较相等,则它们必须具有相同的哈希值。但是两个对象可能发生(不太可能但可能)具有相同的哈希但比较不相等。
  • 这句话的意图正是你所说的。只是它可以像你一样从另一种意义上阅读(应该像“他们已经与 eq 一样”而不是“他们的课程应该被精心设计,以便它们与 eq 比较相等”) - 我会改进文本.
猜你喜欢
  • 2011-06-08
  • 2013-11-29
  • 2013-11-17
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
  • 2012-05-03
  • 2012-04-28
  • 1970-01-01
相关资源
最近更新 更多