Python中“hashable”是什么意思?

时间:2013-01-26 09:48:07

标签: python

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

当他们说对象是hashablehashable objects时是什么意思?

9 个答案:

答案 0 :(得分:137)

来自Python glossary

  

如果对象具有在其生命周期内永远不会更改的哈希值(它需要__hash__()方法),并且可以与其他对象进行比较(它需要__eq__()或{{ 1}}方法)。比较相等的Hashable对象必须具有相同的哈希值。

     

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

     

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

答案 1 :(得分:68)

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

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

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

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

现在,哈希函数可以像将数字除以数组的大小并将余数作为索引一样简单。

有关详细信息,请参阅https://jsfiddle.net/thadeuszlay/p6r2p78g/1/

这是另一个很好的参考:https://en.wikipedia.org/wiki/Hash_function

答案 2 :(得分:10)

任何不可变的东西(可变的意思,可能会改变)都可以进行哈希处理。除了要查找的哈希函数,如果一个类有它,例如。 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

答案 3 :(得分:9)

Hashable =能够被哈希处理。

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

当我在Python 3中运行hash('Python')时,结果为5952713340227947791。不同版本的Python可以自由更改基础哈希函数,因此您可能会获得不同的值。重要的是,无论我现在多次运行hash(‘Python’),还是始终使用相同版本的Python都能获得相同的结果。

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

为什么这很重要?

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

因此,当我们说某事是可哈希的时,我们表示它是不可变的。如果我尝试将可变类型传递给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

答案 4 :(得分:5)

根据Python词汇表的理解,当您创建可清除对象的实例时,还会根据实例的成员或值计算不可更改的值。 例如,该值可以用作dict中的键,如下所示:

>>> 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中的键时,我们可以发现dict_a [tuple_c]的值是相同的,这意味着当它们被用作dict中的键时,它们返回相同的值,因为哈希值是相同。 对于那些不可清除的对象,方法哈希定义为None:

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

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

答案 5 :(得分:4)

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

例如,在python 3.3中:

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

答案 6 :(得分:4)

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

Comparison between 2 tuples Equivalence between 2 tuples

答案 7 :(得分:3)

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

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

答案 8 :(得分:0)

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