“hashable”;在Python中是什么意思?

我试着在网上搜索,但找不到hashable的意思。

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

223880 次浏览

Python术语表:

对象是可哈希的,如果它的哈希值在其生命周期内从未改变(它需要__hash__()方法),并且可以与其他对象进行比较(它需要__eq__()__cmp__()方法)。比较相等的哈希对象必须具有相同的哈希值。

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

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

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

例如,在python 3.3中:

数据结构list是不可哈希的,但数据结构Tuples是可哈希的。

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

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

根据我对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(tuple_a) == id(tuple_c)  # tuple_a and tuple_c same object?
False
>>> tuple_a.__hash__() == tuple_c.__hash__()  # hash of tuple_a and tuple_c same value?
True
>>> dict_a = {}
>>> dict_a[tuple_a] = 'hiahia'
>>> dict_a[tuple_c]
'hiahia'
我们可以发现tuple_atuple_c的哈希值是相同的,因为它们有相同的成员。 当我们在dict_a中使用tuple_a作为键时,我们可以发现dict_a[tuple_c]的值是相同的,这意味着当它们被用作字典中的键时,它们返回相同的值,因为哈希值是相同的。 对于那些不可哈希的对象,__hash__方法定义为None:

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

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

这里的所有答案都很好地解释了python中可哈希对象的工作原理,但我相信人们需要首先理解哈希这个术语。

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

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

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

现在,哈希函数可以非常简单,只需将数字与数组的大小相除,并将余数作为下标。

更多细节请参考https://en.wikipedia.org/wiki/Hash_function

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

任何不可变的东西(可变的意思是,可能会改变)都可以被散列。除了寻找哈希函数,如果一个类有它,通过例如。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
对于从头开始创建哈希表,所有的值都必须设置为“None”,并在需求出现时进行修改。 哈希对象指的是可修改的数据类型(字典,列表等)。另一方面,集一旦被赋值就不能重新初始化,所以集是不可哈希的。然而,set()的变体——frozenset()——是可哈希的

Hashable =能够被哈希。

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

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

但是hash(' Java ')返回1753925553814008565。如果我要哈希的对象改变了,结果也会改变。另一方面,如果我要哈希的对象没有改变,那么结果保持不变。

为什么这很重要?

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

当我们说一个东西是可哈希的,我们指的是它是不可变的。如果我试图将一个可变类型传递给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

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

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

作为其他答案的补充: Python术语表说“作为用户定义类实例的对象在默认情况下是可哈希的”。 但是它还说“比较相等的可哈希对象必须具有相同的哈希值。”

这样,如果你实现了__eq__-Method而没有实现__hash__-Method,你的对象将是不可哈希的。否则,从id()派生哈希将不能保证为两个比较相等的对象生成相同的哈希(id(a) != id(b)a == b)

>>> class Foo(object):
...     def __eq__(self, other): pass
...
>>>
>>> class Bar(object):
...     pass
...
>>> f = Foo()
>>> b = Bar()
>>>
>>> hash(f)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Foo'
>>> hash(b)
8758325844794