原文: http://zetcode.com/python/hashing/

Python 哈希教程解释了 Python 中的哈希概念。 我们介绍了哈希表和 Python 可哈希对象。

哈希表

哈希表用于以许多常见的编程语言(例如 C++ ,Java 和 Python)实现映射和设置数据结构。 Python 将哈希表用于字典和集合。 哈希表是键值对的无序集合,其中每个键都是唯一的。 哈希表提供了有效的查找,插入和删除操作的组合。 这些是数组和链表的最佳属性。

哈希

哈希是使用算法将任意大小的数据映射到固定长度的过程。 这称为哈希值。 哈希用于创建高性能,直接访问的数据结构,在该结构中要快速存储和访问大量数据。 哈希值使用哈希函数计算。

Python 可哈希对象

如果对象的哈希值在其生命周期内从未发生变化,则该对象是可哈希的。 (在多次调用 Python 程序期间,它可以具有不同的值。)可哈希对象需要__hash__()方法。 为了执行比较,哈希需要一种__eq__()方法。

注意:比较相等的可哈希对象必须具有相同的哈希值。

哈希性使对象可用作字典键和集成员,因为这些数据结构在内部使用哈希值。 Python 不可变的内置对象是可哈希的; 可变容器(例如列表或字典)不是。 默认情况下,作为用户定义类实例的对象是可哈希的。 它们都比较不相等(除了它们本身),并且它们的哈希值是从id()派生的。

注意:如果一个类没有定义一个__eq __()方法,它也不应该定义一个__hash __()操作。 如果它定义了__eq __()而不是__hash __(),则其实例将不能用作可哈希集合中的项目。

Python hash()函数

hash()函数返回对象的哈希值(如果有的话)。 哈希值是整数。 它们用于在字典查找期间快速比较字典关键字。 对象可以实现__hash__()方法。

Python 不可变内置函数可哈希化

Python 不变的内置函数(例如整数,字符串或元组)是可哈希的。

builtin_hashables.py

  1. #!/usr/bin/env python3
  2. val = 100
  3. print(val.__hash__())
  4. print("falcon".__hash__())
  5. print((1,).__hash__())

该示例显示三个哈希值的值:整数,字符串和元组。

Python 自定义可哈希对象示例 I

Python 自定义对象默认情况下是可哈希的。 他们的哈希值是从其 ID 派生的。

custom_object.py

  1. #!/usr/bin/env python3
  2. class User:
  3. def __init__(self, name, occupation):
  4. self.name = name
  5. self.occupation = occupation
  6. u1 = User('John Doe', 'gardener')
  7. u2 = User('John Doe', 'gardener')
  8. print('hash of user 1')
  9. print(hash(u1))
  10. print('hash of user 2')
  11. print(hash(u2))
  12. if (u1 == u2):
  13. print('same user')
  14. else:
  15. print('different users')

在示例中,我们有User的两个实例。

  1. u1 = User('John Doe', 'gardener')
  2. u2 = User('John Doe', 'gardener')

我们有两个具有相同数据的实例。

  1. print('hash of user 1')
  2. print(hash(u1))

hash()函数返回对象的哈希值。 默认实现是从对象的 ID 派生的。

  1. $ python custom_object.py
  2. hash of user 1
  3. -9223371894419573195
  4. hash of user 2
  5. 142435202673
  6. different users

即使用户详细信息相同,但比较仍会产生不同的对象。 为了更改它,我们需要实现__eq__()方法。

Python 自定义可哈希对象示例 II

在第二个示例中,我们实现了自定义__eq__()方法。

custom_object2.py

  1. #!/usr/bin/env python3
  2. class User:
  3. def __init__(self, name, occupation):
  4. self.name = name
  5. self.occupation = occupation
  6. def __eq__(self, other):
  7. return self.name == other.name \
  8. and self.occupation == other.occupation
  9. def __str__(self):
  10. return f'{self.name} {self.occupation}'
  11. u1 = User('John Doe', 'gardener')
  12. u2 = User('John Doe', 'gardener')
  13. if (u1 == u2):
  14. print('same user')
  15. print(f'{u1} == {u2}')
  16. else:
  17. print('different users')
  18. # users = {u1, u2}
  19. # print(len(users))

现在比较返回给我们的预期输出; 但是,我们不能将对象插入 Python 集中; 这将导致TypeError: unhashable type: 'User'。 为了更改此设置,我们实现了__hash__()方法。

Python 自定义可哈希对象示例 III

在第三个示例中,我们实现了__eq__()__hash__()方法。

custom_object3.py

  1. #!/usr/bin/env python3
  2. class User:
  3. def __init__(self, name, occupation):
  4. self.name = name
  5. self.occupation = occupation
  6. def __eq__(self, other):
  7. return self.name == other.name \
  8. and self.occupation == other.occupation
  9. def __hash__(self):
  10. return hash((self.name, self.occupation))
  11. def __str__(self):
  12. return f'{self.name} {self.occupation}'
  13. u1 = User('John Doe', 'gardener')
  14. u2 = User('John Doe', 'gardener')
  15. users = {u1, u2}
  16. print(len(users))
  17. if (u1 == u2):
  18. print('same user')
  19. print(f'{u1} == {u2}')
  20. else:
  21. print('different users')
  22. print('------------------------------------')
  23. u1.occupation = 'programmer'
  24. users = {u1, u2}
  25. print(len(users))
  26. if (u1 == u2):
  27. print('same user')
  28. print(f'{u1} == {u2}')
  29. else:
  30. print('different users')

该示例比较了具有__eq__()__hash__()方法的自定义实现的两个对象。 可以将这些对象插入 Python 集中,当以后更改属性时,我们将获得预期的输出。

  1. def __hash__(self):
  2. return hash((self.name, self.occupation))

__hash__()函数的实现从属性元组返回使用hash()函数计算的哈希值。

  1. $ python custom_object3.py
  2. 1
  3. same user
  4. John Doe gardener == John Doe gardener
  5. ------------------------------------
  6. 2
  7. different users

这是输出。

Python @dataclass装饰器

从 Python 3.7 开始,我们有了dataclass装饰器,它会自动生成一些样板代码。

数据类装饰器的冻结参数(默认为False)。 如果指定,则字段将被冻结(即只读)。 如果eq设置为True(默认情况下),则将实现__hash__()方法,并且对象实例将是可哈希的。

decorator.py

  1. #!/usr/bin/env python3
  2. from dataclasses import dataclass
  3. @dataclass(frozen=True)
  4. class User:
  5. name: str
  6. occupation: str
  7. u1 = User('John Doe', 'gardener')
  8. u2 = User('John Doe', 'gardener')
  9. if (u1 == u2):
  10. print('same user')
  11. print(f'{u1} == {u2}')
  12. else:
  13. print('different users')
  14. users = {u1, u2}
  15. print(len(users))

该示例使用@dataclass装饰器。

  1. $ python decorator.py
  2. same user
  3. User(name='John Doe', occupation='gardener') == User(name='John Doe', occupation='gardener')
  4. 1

这是输出。

在本教程中,我们介绍了 Python 中的哈希。

您可能也对以下相关教程感兴趣: Python 教程Python 列表推导或列表所有 Python 教程