ZetCode

Python hash 函数

上次修改时间:2025 年 4 月 11 日

本综合指南探讨 Python 的 hash 函数,该函数返回对象的哈希值。我们将介绍基本用法、可哈希类型、自定义对象以及 Python 中哈希的实际示例。

基本定义

hash 函数返回一个整数,表示对象的哈希值。哈希值用于快速比较字典键和集合成员。

关键特征:适用于不可变对象,在对象的生命周期内(每个 Python 会话)返回相同的值,对于不可哈希的类型引发 TypeError。不保证哈希值是唯一的。

内置类型的基本用法

这是一个简单的用法,使用不同的内置类型,展示了 hash 如何处理数字、字符串和元组。

basic_hash.py
# 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 运行和版本而异。

不可哈希的类型

像列表和字典这样的可变类型是不可哈希的。此示例显示了尝试哈希它们时会发生什么。

unhashable.py
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 类。

custom_hash.py
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 会话中保持一致,但可能会在运行之间发生变化。此示例演示了此行为。

consistency.py
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 字典和集合的基础。此示例显示了哈希值如何实现高效查找。

data_structures.py
# 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__

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出所有 Python 教程