【问题标题】:Is it a good idea to generate and store a random number as a hash value for my class?生成一个随机数并将其存储为我的班级的哈希值是个好主意吗?
【发布时间】:2011-02-18 21:38:46
【问题描述】:

我有一个基本上包装列表的类,而列表显然不能有哈希值。我的想法是生成一个随机数并将其存储为哈希值。

【问题讨论】:

  • 如果您尝试将您的类用作字典键(例如),您的意思是您得到一个 TypeError: unhashable type 吗?请参阅this previous answer 为什么会这样。您能否提供更多有关您正在尝试做的事情的信息?

标签: python hash


【解决方案1】:

如果您有两个等效的实例,则它们必须返回相同的 __hash__ 值。如果你随机生成一个,你不能保证会这样,所以你会得到奇怪的行为。

你能用元组代替列表吗?您可以在计算哈希时忽略列表吗?不相等的物体发生碰撞也没关系。

您应该看到DictionaryKeys 了解为什么不允许列表包含哈希值。

【讨论】:

  • 或者,可能“冻结”列表以使其正常工作。这通常意味着从包装列表的类到包装元组的非常相似的类的浅拷贝。通常使用 freeze() 的方法名称。
  • 您可以通过使用tuple(yourlist) 来执行此操作,它只会获取列表的副本。虽然它是不可变的,但不知道 OP 是否需要它是可变的。
  • 如果您在构造函数中生成哈希并将其存储为成员数据,那么每次调用哈希方法都会自然地从该成员返回相同的值。
  • @Steve314 - 这如何解决执行__hash__ 合同的问题?
  • @sjr - 同一个实例始终具有相同的哈希值。正如我在回答中所说,这可能是有效的(识别实例,因此您正在查找的“值”是参考) - 尽管它会导致问题“为什么?”。我能想到的唯一理智的答案是一组实例,因此您不会两次添加相同的实例(无论值如何)。一个奇怪的要求,但并非不可能。
【解决方案2】:

不是一个好主意。哈希码的一般约定是,如果对象 A 等于对象 B,则 A.hashCode() 等于 B.hashCode()。以你的提议,这不会成立。

你可以试试

  • 列表长度作为哈希码
  • 列表中第一项的哈希码作为哈希码
  • 所有项目的所有hashcode之和作为hashcode

或其他类似的东西。

【讨论】:

  • 查看@sjr 回答中的链接,了解为什么即使这不是一个好主意,即使它在技术上符合合同要求。
【解决方案3】:

正如其他人所提到的,如果 2 个对象被认为是“相等的”,那么它们必须具有相同的哈希值。

如何为班级定义equals 取决于您。如果你只关心引用相等,那么你可以在__init__ 上生成一个随机数,但最好是MyWrapper([1,2,3]) == MyWrapper([1,2,3])False

您不应该像@iluxa 建议的那样将列表的内容用作散列的原因是,如果您将类用作字典中的键,然后更改内容以使散列值发生变化,则不会能够在字典中找到该键,因为它存储了旧的哈希值并正在尝试查找新的。

总结一下:

  1. 如果a == bhash(a) == hash(b) 必须为真。
  2. 如果a != b 那么hash(a) != hash(b) 应该是 大多数时候是真的 查找的性能,但它是 不必如此。
  3. 该 哈希值不应该改变 在将其添加到 dict(或任何其他基于散列的 查找结构不 在查找时重新计算哈希值) 并试图找到它。

最后一部分通常只是简化为不应该改变的哈希值。

【讨论】:

【解决方案4】:

支持对可变容器进行散列是合理的 - 但一般规则是散列当前值,而不是容器。

编辑这在原则上是合理的,尽管 Python 通常会防范它。

对于这类任务,甚至还有一种特定的散列技术。 Zobrist 散列基于对容器的每次更改以增量方式计算散列,这样无论您如何达到特定值,您都会获得相同的散列。这在国际象棋程序中用于检测棋盘通过不同的移动序列达到相同状态的情况,作为对博弈树搜索的优化。

这里的问题是为什么您要使用基于哈希的查找来查找列表?

如果值不同,但无论如何您都想找到相同的容器,那么这可能会起作用(存在碰撞问题)-但这似乎仍然毫无意义。随机哈希值只是一种标识符,用于标识您所指的对象。对象的引用/指针是一个 better 标识符。如果您还没有对该对象的引用,您如何知道要搜索哪个哈希值?

如果您想要一个容器集合,列表列表是比随机散列列表字典更好的解决方案。

编辑 一个可能的例外是,如果您想要一个列表集合,其中同一个列表可能会被添加多次,但在容器中只会出现一次 - 一组列表实例。在这种情况下,哈希应该基于对对象的引用,但我不记得是如何完成的。

【讨论】:

    猜你喜欢
    • 2017-10-05
    • 2018-11-18
    • 1970-01-01
    • 2021-02-15
    • 2016-05-01
    • 1970-01-01
    • 2016-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多