【发布时间】:2019-09-24 13:01:56
【问题描述】:
我来自 Java,即使是可变对象也可以是“可散列的”。
这些天我玩 Python 3.x 只是为了好玩。
这是 Python 中 hashable 的定义(来自 Python 词汇表)。
可散列
如果一个对象有一个在其生命周期内永远不会改变的哈希值(它需要一个
__hash__()方法),并且可以与其他对象进行比较(它需要一个__eq__()方法),那么它就是可哈希的。比较相等的可散列对象必须具有相同的散列值。Hashability 使对象可用作字典键和集合成员,因为这些数据结构在内部使用哈希值。
所有 Python 的不可变内置对象都是可散列的;可变容器(例如列表或字典)不是。默认情况下,作为用户定义类实例的对象是可散列的。它们都比较不相等(除了它们自己),它们的哈希值来自它们的
id()。
我读了它,我在想...... 仍然......为什么他们在 Python 中甚至不使可变对象成为可哈希对象?例如。使用与用户定义对象相同的 default 散列机制,即如上面最后两句所述。
默认情况下,作为用户定义类实例的对象是可散列的。它们都比较不相等(除了它们自己),它们的哈希值来自它们的 id()。
这感觉有点奇怪......所以用户定义的可变对象是可散列的(通过此默认散列机制),但内置的可变对象不可散列。这不只是使事情复杂化了吗?我看不出它带来了什么好处,有人可以解释一下吗?
【问题讨论】:
-
要散列一个列表,你必须首先散列其中的所有内容;因为它是可变的,所以对它的任何更改都应该更改哈希。要散列一个元组,散列它的
id()就足够了,因为它不能被修改。用户通常期望散列用户定义的类的行为更像一个不可变对象(即使它是可变的),所以它就是这样做的,当然你可以让它以任何你喜欢的方式运行。 -
@kindall:元组不是由
id散列的。 -
@kindall 嗯...谁说哈希值必须来自列表中的值?如果你例如添加一个新值,您必须重新散列列表,获取新的散列值等。在其他语言中,情况并非如此......这是我的观点。在其他语言中,哈希值仅来自 id(或者是 id 本身,就像用户定义的可变 Python 对象一样)......好吧......我只是觉得它让 Python 中的事情有点太复杂了(尤其是对于初学者......不适合我)。无论如何...感谢这里的所有答案,我会继续关注新的答案。
-
@peter.petrov:在 Java 中,您来自的语言,集合
hashCode值是基于容器内容。例如,here are the List docs。其他任何东西都会被破坏和/或无用,因为equals是基于集合内容的。 -
“通过让你将基于可变状态散列的可变对象放入 HashMaps”哇...我假设在 Java 中他们不会基于可变状态对列表进行散列,而只是基于 id 或其他东西(就像 Python 对其可变的用户定义对象所做的那样)。这个假设是错误的......这真的很奇怪(我的意思是Java方式)......所以我在这里问了一个关于Python的问题......但也学习(或刷新)了一些关于Java的东西。这确实是 Java 中的奇怪行为。我也不喜欢。现在,Python 方式对我来说确实更有意义。
标签: python python-3.x