hash在python中做什么?

时间:2013-07-11 05:32:50

标签: python hash

我看到了一个代码示例,其中hash函数应用于元组。结果它返回一个负整数。我想知道这个功能是做什么的。谷歌没有帮助。我找到了一个页面,解释了如何计算哈希值,但它没有解释为什么我们需要这个函数。

5 个答案:

答案 0 :(得分:104)

A hash is an fixed sized integer that identifies a particular value。每个值都需要有自己的哈希值,因此对于相同的值,即使它不是同一个对象,也会获得相同的哈希值。

>>> hash("Look at me!")
4343814758193556824
>>> f = "Look at me!"
>>> hash(f)
4343814758193556824

需要以这样的方式创建散列值,使得结果值均匀分布,以减少您获得的散列冲突的数量。散列冲突是指两个不同的值具有相同的散列。因此,相对较小的变化通常会导致非常不同的哈希值。

>>> hash("Look at me!!")
6941904779894686356

这些数字非常有用,因为它们可以快速查找大量值中的值。它们使用的两个例子是Python的setdict。在list中,如果要使用if x in values:检查列表中是否包含值,则Python需要遍历整个列表并将x与列表中的每个值进行比较{ {1}}。长values这可能需要很长时间。在list中,Python会跟踪每个哈希值,当您键入set时,Python将获取if x in values:的哈希值,在内部结构中查找,然后仅进行比较x的值与x具有相同的哈希值。

相同的方法用于字典查找。这使得xset中的查找速度非常快,而dict中的查找速度很慢。这也意味着您可以在list中使用不可浏览的对象,但不能在list中或set中的键。不可清除对象的典型示例是任何可变的对象,这意味着您可以更改其值。如果你有一个可变对象,它不应该是可散列的,因为它的散列会在其生命周期内发生变化,这会引起很多混乱,因为一个对象最终会在字典中的错误散列值下结束。

请注意,对于一次Python运行,值的哈希值只需要相同。在Python 3.3中,它们实际上会针对每次新的Python运行进行更改:

dict

这使得更难以猜测某个字符串将具有哪个哈希值,这是Web应用程序等的重要安全功能。

因此,不应永久存储散列值。如果您需要以永久方式使用哈希值,您可以查看更严重的哈希类型cryptographic hash functions,它们可用于制作可验证的文件校验和等。

答案 1 :(得分:25)

TL; DR:

请参阅the glossaryhash()用作比较对象的快捷方式,如果可以将对象与其他对象进行比较,则该对象被视为可清除。这就是我们使用hash()的原因。它还用于访问以resizable hash tables in CPython实现的dictset个元素。

技术考虑

  • 通常比较对象(可能涉及多个级别的递归)很昂贵。
  • 优选地,hash()函数是较便宜的数量级(或几个)。
  • 比较两个哈希比比较两个对象更容易,这就是快捷方式所在。

如果您阅读how dictionaries are implemented,他们会使用哈希表,这意味着从对象中获取密钥是在O(1)中检索词典中对象的基石。然而,这非常依赖于您的哈希函数抗冲突。字典中的worst case for getting an item实际上是O(n)

在这方面,可变对象通常是不可清除的。 hashable属性意味着您可以将对象用作键。如果哈希值用作键并且同一对象的内容发生更改,那么哈希函数应该返回什么?是同一把钥匙还是另一把钥匙? 取决于如何定义哈希函数。

通过实例学习:

想象一下,我们有这个课程:

>>> class Person(object):
...     def __init__(self, name, ssn, address):
...         self.name = name
...         self.ssn = ssn
...         self.address = address
...     def __hash__(self):
...         return hash(self.ssn)
...     def __eq__(self, other):
...         return self.ssn == other.ssn
... 

请注意:这都是基于SSN永远不会改变个人的假设(甚至不知道从权威来源实际验证该事实的位置)。

我们有鲍勃:

>>> bob = Person('bob', '1111-222-333', None)
鲍勃去看法官改名:

>>> jim = Person('jim bo', '1111-222-333', 'sf bay area')

这就是我们所知道的:

>>> bob == jim
True

但这些是分配了不同内存的两个不同对象,就像同一个人的两个不同记录一样:

>>> bob is jim
False

现在,hash()很方便:

>>> dmv_appointments = {}
>>> dmv_appointments[bob] = 'tomorrow'

猜猜:

>>> dmv_appointments[jim] #?
'tomorrow'

您可以从两个不同的记录中访问相同的信息。 现在试试这个:

>>> dmv_appointments[hash(jim)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in __eq__
AttributeError: 'int' object has no attribute 'ssn'
>>> hash(jim) == hash(hash(jim))
True

刚刚发生了什么?那是一次碰撞。因为hash(jim) == hash(hash(jim))都是整数btw,我们需要将__getitem__的输入与碰撞的所有项进行比较。内置int没有ssn属性,因此它会跳转。

>>> del Person.__eq__
>>> dmv_appointments[bob]
'tomorrow'
>>> dmv_appointments[jim]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: <__main__.Person object at 0x7f611bd37110>

在最后一个例子中,我表明即使碰撞,也会进行比较,对象不再相等,这意味着它成功地引发了KeyError

答案 2 :(得分:2)

Python docs for hash()状态:

  

哈希值是整数。它们用于在字典查找期间快速比较字典键。

Python字典作为哈希表实现。因此,只要您使用字典,就会在传入的键上调用hash()进行分配或查找。

此外,docs for the dict type州:

  

不是 hashable 的值,即包含列表,字典或其他可变类型(通过值而不是按对象标识进行比较)的值不能用作键。

答案 3 :(得分:1)

字典和集合使用哈希来快速查找对象。一个很好的起点是维基百科关于hash tables的文章。

答案 4 :(得分:0)

我也在很长一段时间内在寻找它,现在我得到了我的答案,所以你们所有人都感到不安...

请在python中使用 Dictionary 数据类型,它非常类似于 hash 它也支持嵌套,类似于嵌套的哈希。

示例:-

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School" # Add new entry

print ("dict['Age']: ", dict['Age'])
print ("dict['School']: ", dict['School'])
  

字典数据类型:-   https://www.tutorialspoint.com/python3/python_dictionary.htm

希望它可以解决问题。