你在Python中使用hashable是什么意思?

use*_*071 163 python

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

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

NPE*_*NPE 154

Python术语表:

一个目的是可哈希如果它有一个哈希值其寿命(它需要一个在这期间从不改变__hash__()方法),并且可相对于其他对象(它需要一个__eq__()__cmp__()方法).比较相等的可哈希对象必须具有相同的哈希值.

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

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

  • @TorstenBronger:因为两个不相等的对象可以散列到相同的值.换句话说,散列是有损的. (15认同)
  • 如果它现在有“哈希值”,那么哈希值是什么。你能举一些例子吗 (5认同)
  • 我知道这是一篇旧帖子,但值得一提的是,这里复制的词汇表条目并不完全正确。您可以将可变对象(如列表)放入元组中。元组仍然是不可变的,但是您可以更改其中的列表,因此它不是可散列的。试试 `hash((1, [2, 3]))` 看看它的实际效果。我已经发布了一个请求来更正 hashable 的词汇表条目。 (3认同)
  • @ user55711:这里,哈希值是调用`__hash __()`的结果.更一般地,请参阅http://en.wikipedia.org/wiki/Hash_function (2认同)
  • 在python-2.7.12中,`id(object)`的结果是`object.__hash__()`的16倍。所以这个版本的词汇表摘录是不正确的——哈希值不是`id()`,而是从它派生出来的(正如python 2.7.12的更新文档中所指出的那样)。 (2认同)
  • 正如 @JohnRiehl 指出的,最近的术语表文档确实提到了这一点:“不可变容器(例如元组和冻结集)只有在其元素可哈希时才可哈希。” 根据此 [py 3.9 术语表](https://docs.python.org/3.9/glossary.html) 。 (2认同)

小智 84

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

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

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

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

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

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

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

  • 您能否生成一些有关电话号码数组场景的简单代码来阐明散列的概念? (3认同)
  • 这是关于哈希的一个有趣的观点。我还没有这样想过。 (2认同)

use*_*754 12

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

不可变类型列表:

int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes
Run Code Online (Sandbox Code Playgroud)

可变类型列表:

list, dict, set, bytearray, user-defined classes
Run Code Online (Sandbox Code Playgroud)

  • @GáborFekete 用户定义类的实例是可散列的,如果它们的类实现了 `__hash__` 和 `__eq__`。此外,所有用户定义的类都实现了这些方法(因此是可散列的),因为它们从`object`(通用基类)继承了方法。 (2认同)

Sid*_*qui 12

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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,Python 在每个进程开始时随机播种哈希算法。因此,如果在不同的进程中运行 hash('Python') 两次,实际上会得到不同的哈希值。 (3认同)

小智 9

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

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


小智 6

根据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'
Run Code Online (Sandbox Code Playgroud)

我们可以发现tuple_a和tuple_c的哈希值是相同的,因为它们具有相同的成员.当我们使用tuple_a作为dict_a中的键时,我们可以发现dict_a [tuple_c]的值是相同的,这意味着当它们被用作dict中的键时,它们返回相同的值,因为哈希值是相同.对于那些不可清除的对象,方法哈希定义为None:

>>> type(dict.__hash__) 
<class 'NoneType'>
Run Code Online (Sandbox Code Playgroud)

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

  • “我们可以发现tuple_a和tuple_c的哈希值是相同的,因为它们具有相同的成员。” - 这有点误导。拥有相同的成员还不够,成员的顺序也很重要。 (2认同)