286

我尝试搜索互联网,但找不到 hashable 的含义。

当他们说物体是hashable或者hashable objects是什么意思?

4

9 回答 9

242

来自Python 词汇表

如果一个对象的哈希值在其生命周期内永远不会改变(它需要一个__hash__()方法),并且可以与其他对象进行比较(它需要一个__eq__()or__cmp__()方法),那么它就是可哈希的。比较相等的可散列对象必须具有相同的散列值。

哈希性使对象可用作字典键和集合成员,因为这些数据结构在内部使用哈希值。

Python 的所有不可变内置对象都是可散列的,而没有可变容器(例如列表或字典)是可散列的。默认情况下,作为用户定义类实例的对象是可散列的;它们都比较不相等,它们的哈希值是它们的id().

于 2013-01-26T09:49:08.690 回答
137

这里的所有答案对 python 中的可散列对象都有很好的解释,但我相信首先需要理解散列这个术语。

散列是计算机科学中的一个概念,用于创建高性能、伪随机访问数据结构,其中大量数据将被快速存储和访问。

例如,如果您有 10,000 个电话号码,并且您希望将它们存储在一个数组中(这是一种将数据存储在连续内存位置并提供随机访问的顺序数据结构),但您可能没有所需数量的连续内存位置。

因此,您可以改为使用大小为 100 的数组,并使用哈希函数将一组值映射到相同的索引,这些值可以存储在链表中。这提供了类似于数组的性能。

现在,哈希函数可以简单到将数字除以数组的大小,然后将余数作为索引。

有关更多详细信息,请参阅https://en.wikipedia.org/wiki/Hash_function

这是另一个很好的参考:http: //interactivepython.org/runestone/static/pythonds/SortSearch/Hashing.html

于 2016-06-23T08:44:55.300 回答
27

任何不可变的(可变的手段,可能会改变)都可以被散列。除了要查找的哈希函数,如果一个类有它,例如。dir(tuple)并寻找__hash__方法,这里有一些例子

#x = hash(set([1,2])) #set unhashable
x = hash(frozenset([1,2])) #hashable
#x = hash(([1,2], [2,3])) #tuple of mutable objects, unhashable
x = hash((1,2,3)) #tuple of immutable objects, hashable
#x = hash()
#x = hash({1,2}) #list of mutable objects, unhashable
#x = hash([1,2,3]) #list of immutable objects, unhashable

不可变类型列表:

int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes

可变类型列表:

list, dict, set, bytearray, user-defined classes
于 2017-07-03T08:20:01.717 回答
26

根据Python词汇表的理解,当您创建可散列的对象实例时,也会根据实例的成员或值计算出一个不可更改的值。例如,该值可以用作字典中的键,如下所示:

>>> tuple_a = (1, 2, 3)
>>> tuple_a.__hash__()
2528502973977326415
>>> tuple_b = (2, 3, 4)
>>> tuple_b.__hash__()
3789705017596477050
>>> tuple_c = (1, 2, 3)
>>> tuple_c.__hash__()
2528502973977326415
>>> id(a) == id(c)  # a and c same object?
False
>>> a.__hash__() == c.__hash__()  # a and c same value?
True
>>> dict_a = {}
>>> dict_a[tuple_a] = 'hiahia'
>>> dict_a[tuple_c]
'hiahia'

我们可以发现 和 的哈希值tuple_a相同tuple_c,因为它们具有相同的成员。当我们tuple_a用作 中的键时dict_a,我们可以发现 for 的值dict_a[tuple_c]是相同的,这意味着当它们用作字典中的键时,它们返回相同的值,因为哈希值相同。对于那些不可散列的对象,该方法__hash__定义为None

>>> type(dict.__hash__) 
<class 'NoneType'>

我猜这个哈希值是在实例初始化时计算的,而不是以动态方式计算的,这就是为什么只有不可变对象是可哈希的。希望这可以帮助。

于 2016-05-25T06:45:26.413 回答
16

Hashable = 能够被散列。

好的,什么是哈希?散列函数是一个函数,它接受一个对象,比如“Python”之类的字符串,并返回一个固定大小的代码。为简单起见,假设返回值是一个整数。

当我在 Python 3 中运行 hash('Python') 时,我得到 5952713340227947791 作为结果。不同版本的 Python 可以自由更改底层哈希函数,因此您可能会得到不同的值。重要的是,无论现在我运行多少次 hash('Python'),使用相同版本的 Python 总是会得到相同的结果。

但是 hash('Java') 返回 1753925553814008565。因此,如果我正在散列的对象发生变化,结果也会发生变化。另一方面,如果我正在散列的对象没有改变,那么结果保持不变。

为什么这很重要?

例如,Python 字典要求键是不可变的。也就是说,键必须是不变的对象。字符串在 Python 中是不可变的,其他基本类型(int、float、bool)也是如此。元组和冻结集也是不可变的。另一方面,列表不是不可变的(即它们是可变的),因为您可以更改它们。同样,dicts 是可变的。

所以当我们说某些东西是可散列的,我们的意思是它是不可变的。如果我尝试将可变类型传递给 hash() 函数,它将失败:

>>> hash('Python')
1687380313081734297
>>> hash('Java')
1753925553814008565
>>>
>>> hash([1, 2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash({1, 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> hash({1 : 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
>>> hash(frozenset({1, 2}))
-1834016341293975159
>>> hash((1, 2))
3713081631934410656
于 2020-05-19T12:07:41.387 回答
11

在 Python 中,任何不可变对象(例如整数、布尔值、字符串、元组)都是可散列的,这意味着它的值在其生命周期内不会改变。这允许 Python 创建一个唯一的哈希值来识别它,字典可以使用它来跟踪唯一的键和集合来跟踪唯一的值。

这就是 Python 要求我们对字典中的键使用不可变数据类型的原因。

于 2020-05-29T00:13:44.767 回答
3

在 python 中,这意味着对象可以是集合的成员,以便返回索引。也就是说,它们具有唯一的身份/ id。

例如,在 python 3.3 中:

数据结构列表是不可散列的,但数据结构元组是可散列的。

于 2013-09-14T20:31:47.743 回答
3

让我给你一个工作示例来理解 python 中的可散列对象。我在这个例子中使用了 2 个元组。元组中的每个值都有一个唯一的哈希值,它在其生命周期内永远不会改变。所以基于这个有值,两个元组之间的比较就完成了。我们可以使用 Id() 获取元组元素的哈希值。

2个元组之间的比较2个元组之间的等价

于 2015-06-15T07:30:15.547 回答
-3

为了从头开始创建哈希表,所有值都必须设置为“无”,并在出现需求时进行修改。可散列对象是指可修改的数据类型(字典、列表等)。另一方面,集合一旦分配就不能重新初始化,因此集合是不可散列的。而 set() 的变体——frozenset()——是可散列的。

于 2019-11-04T06:59:59.880 回答