Python hash()函数

时间:2020-02-23 14:42:46  来源:igfitidea点击:

Python hash()是内置函数之一。
今天,我们将研究hash()函数的用法以及如何为自定义对象覆盖它。

什么是哈希?

用最简单的术语来说,哈希是标识特定值的固定大小的整数。
请注意,这是最简单的解释。

让我们指出固定哈希值的含义:

  • 相同的数据将具有相同的哈希值。

  • 即使原始数据稍有变化,也可能导致完全不同的哈希值。

  • 从哈希函数获得哈希,哈希函数负责将给定信息转换为编码哈希。

  • 显然,对象的数量可以远远大于哈希值的数量,因此,两个对象可以哈希为相同的哈希值。
    这称为哈希冲突。
    这意味着,如果两个对象具有相同的哈希码,则它们不一定具有相同的值。

什么是Python哈希函数?

我们可以深入介绍有关散列的细节,但是在此处值得一提的是有关制作GOOD Hash函数的重要一点:

一个好的哈希函数是导致冲突次数最少的函数,这意味着,没有2组信息应该具有相同的哈希值。

除了上述定义之外,就空间和内存复杂性而言,对象的哈希值应该便宜。

在完成字典键的比较时,最常用哈希码。
当对特定键进行字典查找时,将比较字典键的哈希码。
比较散列比比较完整键值要快得多,因为散列函数将每个字典键映射到的整数集远小于对象集本身。

另外,请注意,如果两个数值可以比较相等,则即使它们属于不同的数据类型(例如1和1.0),它们也将具有相同的哈希值。

Python hash()字符串

让我们开始构建简单的示例和场景,其中的hash()函数可能会非常有帮助。
在此示例中,我们将简单地获取String的哈希值。

name = "Shubham"

hash1 = hash(name)
hash2 = hash(name)

print("Hash 1: %s" % hash1)
print("Hash 2: %s" % hash2)

运行此脚本时,将获得以下结果:

这是一个重要的收获。
如果再次运行相同的脚本,则哈希值将发生如下变化:

因此,哈希的寿命仅适用于程序范围,并且可以在程序结束后立即更改。

Python哈希值略有变化

其中我们将看到数据的微小变化如何改变哈希值。
它会完全改变还是改变一点?更好的方法是通过脚本找出答案!

name1 = "Shubham"
name2 = "Shubham!"

hash1 = hash(name1)
hash2 = hash(name2)

print("Hash 1: %s" % hash1)
print("Hash 2: %s" % hash2)

现在运行此脚本:

看看当原始数据中只有一个字符改变时,哈希如何完全改变?这使得哈希值完全不可预测!

如何为自定义对象定义hash()函数?

在内部,hash()函数通过覆盖__hash __()函数来工作。
值得注意的是,并非每个对象都是可哈希的(可变集合不是哈希的)。
我们还可以为我们的自定义类定义此函数。
实际上,这就是我们现在要做的。
在此之前,让我们指出一些要点:

  • 对于可变集合,不应执行可哈希实现,因为集合的键对于哈希而言应是不可变的。

  • 我们不必为所有对象都定义一个自定义的__eq __()函数实现。

现在,让我们定义一个对象并覆盖__hash __()函数:

class Student:
  def __init__(self, age, name):
      self.age = age
      self.name = name

  def __eq__(self, other):
      return self.age == other.age and self.name == other.name

  def __hash__(self):
      return hash((self.age, self.name))

student = Student(23, 'Shubham')
print("The hash is: %d" % hash(student))

该程序实际上描述了我们如何覆盖__eq __()__hash __()函数。
这样,我们实际上可以定义自己的逻辑来比较任何对象。

为什么可变的对象不能散列?

众所周知,只能对不可变的对象进行哈希处理。
不允许对可变对象进行哈希处理的限制大大简化了哈希表。
让我们了解如何。

如果允许对可变对象进行哈希处理,则每次对象值更新时,我们都需要更新哈希表。
这意味着我们将不得不将对象移动到完全不同的存储桶中。
这是要执行的非常昂贵的操作。

在Python中,我们有两个使用哈希表的对象,字典和集合:

  • 词典是一个哈希表,称为关联数组。
    在字典中,仅对键进行哈希处理,而不对值进行哈希处理。
    这就是为什么字典键也应该是不可变对象的原因,而值可以是任何值,甚至是可变的列表。

  • 一组包含可哈希的唯一对象。
    如果我们有不可散列的项目,则不能使用set,而必须使用list。