Python hash 函数
上次修改时间:2025 年 4 月 11 日
本综合指南探讨 Python 的 hash 函数,该函数返回对象的哈希值。我们将介绍基本用法、可哈希类型、自定义对象以及 Python 中哈希的实际示例。
基本定义
hash 函数返回一个整数,表示对象的哈希值。哈希值用于快速比较字典键和集合成员。
关键特征:适用于不可变对象,在对象的生命周期内(每个 Python 会话)返回相同的值,对于不可哈希的类型引发 TypeError。不保证哈希值是唯一的。
内置类型的基本用法
这是一个简单的用法,使用不同的内置类型,展示了 hash 如何处理数字、字符串和元组。
# With integers
print(hash(42)) # 42
print(hash(-100)) # -100
# With floats
print(hash(3.14)) # 322818021289917443
# With strings
print(hash("hello")) # -1267296259
# With tuples (immutable)
print(hash((1, 2, 3))) # 529344067295497451
此示例显示了 hash 与不同不可变类型的使用。整数通常哈希到它们本身,而其他类型则产生更复杂的值。
请注意,由于安全原因,随机哈希种子,哈希值可能因 Python 运行和版本而异。
不可哈希的类型
像列表和字典这样的可变类型是不可哈希的。此示例显示了尝试哈希它们时会发生什么。
try:
print(hash([1, 2, 3]))
except TypeError as e:
print(f"Error: {e}") # unhashable type: 'list'
try:
print(hash({"a": 1}))
except TypeError as e:
print(f"Error: {e}") # unhashable type: 'dict'
这些示例演示了 hash 对可变类型的行为。列表和字典会引发 TypeError,因为它们可以更改。
要使可变对象可哈希,您需要使其不可变(例如,将列表转换为元组)或实现自定义哈希逻辑。
带有 __hash__ 的自定义对象
您可以通过实现 __hash__ 方法使自定义对象可哈希。此示例创建一个 Point 类。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __hash__(self):
return hash((self.x, self.y))
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __repr__(self):
return f"Point({self.x}, {self.y})"
p1 = Point(1, 2)
p2 = Point(1, 2)
print(hash(p1)) # Same as hash((1, 2))
print(hash(p2)) # Same as hash(p1)
Point 类使用其坐标的哈希值实现 __hash__。当我们在 Point 实例上调用 hash 时,Python 会使用此方法。
请注意,比较相等的对象应具有相同的哈希值,因此 __eq__ 的实现也很重要。
会话内的哈希一致性
哈希值在一个 Python 会话中保持一致,但可能会在运行之间发生变化。此示例演示了此行为。
s = "Python"
h1 = hash(s)
h2 = hash(s)
print(h1 == h2) # True within same session
# Restart Python and hash may be different
print("Hash value in this run:", h1)
这表明哈希值在单个 Python 会话期间保持不变。但是,由于哈希随机化,它们可能在运行之间有所不同。
哈希随机化是一项安全功能,可防止某些类型的拒绝服务攻击。
数据结构中的实际用法
哈希是 Python 字典和集合的基础。此示例显示了哈希值如何实现高效查找。
# Dictionary relies on hash values
d = {"apple": 1, "banana": 2}
print("apple" in d) # Fast lookup using hash
# Set uses hashing for membership tests
s = {1, 2, 3, 4, 5}
print(3 in s) # Fast lookup using hash
# Custom objects in sets
points = {Point(1, 2), Point(3, 4)}
print(Point(1, 2) in points) # True
这演示了哈希值如何实现字典和集合中的高效成员资格测试。相同的原则适用于自定义对象。
对于自定义对象,要在集合/字典中正确工作,必须正确实现 __hash__ 和 __eq__。
最佳实践
- 使用不可变对象: 仅哈希不可变对象
- 实现 __hash__ 和 __eq__: 对于自定义可哈希类型
- 不要依赖特定的哈希值: 它们在运行之间会发生变化
- 考虑性能: 简单的哈希函数更快
- 保持哈希一致性: 相等的对象必须具有相同的哈希值
资料来源
作者
列出所有 Python 教程。