【发布时间】:2011-02-18 21:38:46
【问题描述】:
我有一个基本上包装列表的类,而列表显然不能有哈希值。我的想法是生成一个随机数并将其存储为哈希值。
【问题讨论】:
-
如果您尝试将您的类用作字典键(例如),您的意思是您得到一个 TypeError: unhashable type 吗?请参阅this previous answer 为什么会这样。您能否提供更多有关您正在尝试做的事情的信息?
我有一个基本上包装列表的类,而列表显然不能有哈希值。我的想法是生成一个随机数并将其存储为哈希值。
【问题讨论】:
如果您有两个等效的实例,则它们必须返回相同的 __hash__ 值。如果你随机生成一个,你不能保证会这样,所以你会得到奇怪的行为。
你能用元组代替列表吗?您可以在计算哈希时忽略列表吗?不相等的物体发生碰撞也没关系。
您应该看到DictionaryKeys 了解为什么不允许列表包含哈希值。
【讨论】:
freeze() 的方法名称。
tuple(yourlist) 来执行此操作,它只会获取列表的副本。虽然它是不可变的,但不知道 OP 是否需要它是可变的。
__hash__ 合同的问题?
不是一个好主意。哈希码的一般约定是,如果对象 A 等于对象 B,则 A.hashCode() 等于 B.hashCode()。以你的提议,这不会成立。
你可以试试
或其他类似的东西。
【讨论】:
正如其他人所提到的,如果 2 个对象被认为是“相等的”,那么它们必须具有相同的哈希值。
如何为班级定义equals 取决于您。如果你只关心引用相等,那么你可以在__init__ 上生成一个随机数,但最好是MyWrapper([1,2,3]) == MyWrapper([1,2,3]) 是False。
您不应该像@iluxa 建议的那样将列表的内容用作散列的原因是,如果您将类用作字典中的键,然后更改内容以使散列值发生变化,则不会能够在字典中找到该键,因为它存储了旧的哈希值并正在尝试查找新的。
总结一下:
a == b 则hash(a) ==
hash(b) 必须为真。 a != b
那么hash(a) != hash(b) 应该是
大多数时候是真的
查找的性能,但它是
不必如此。 dict(或任何其他基于散列的
查找结构不
在查找时重新计算哈希值)
并试图找到它。最后一部分通常只是简化为不应该改变的哈希值。
【讨论】:
支持对可变容器进行散列是合理的 - 但一般规则是散列当前值,而不是容器。
编辑这在原则上是合理的,尽管 Python 通常会防范它。
对于这类任务,甚至还有一种特定的散列技术。 Zobrist 散列基于对容器的每次更改以增量方式计算散列,这样无论您如何达到特定值,您都会获得相同的散列。这在国际象棋程序中用于检测棋盘通过不同的移动序列达到相同状态的情况,作为对博弈树搜索的优化。
这里的问题是为什么您要使用基于哈希的查找来查找列表?
如果值不同,但无论如何您都想找到相同的容器,那么这可能会起作用(存在碰撞问题)-但这似乎仍然毫无意义。随机哈希值只是一种标识符,用于标识您所指的对象。对象的引用/指针是一个 better 标识符。如果您还没有对该对象的引用,您如何知道要搜索哪个哈希值?
如果您想要一个容器集合,列表列表是比随机散列列表字典更好的解决方案。
编辑 一个可能的例外是,如果您想要一个列表集合,其中同一个列表可能会被添加多次,但在容器中只会出现一次 - 一组列表实例。在这种情况下,哈希应该基于对对象的引用,但我不记得是如何完成的。
【讨论】: