Python哈希教程解释了Python中的哈希概念。我们解释了哈希表和Python可哈希对象。
哈希表
哈希表用于在许多常见的编程语言(例如C++、Java和Python)中实现映射和集合数据结构。Python对字典和集合使用哈希表。哈希表是键值对的无序集合,其中每个键都是唯一的。哈希表提供了高效查找、插入和删除操作的组合。这些是数组和链表的最佳属性。
散列
Hashing是使用算法将任意大小的数据映射到固定长度的过程。这称为散列值。散列用于创建高性能、直接访问的数据结构,其中大量数据将被快速存储和访问。哈希值是用哈希函数计算的。
Python可哈希
如果一个对象的哈希值在其生命周期内永不改变,则该对象是可哈希的。(在多次调用Python程序期间它可以有不同的值。)可散列对象需要一个__hash__
方法。为了执行比较,可散列需要一个__eq__
方法。
可哈希性使对象可用作字典键和集合成员,因为这些数据结构在内部使用哈希值。Python不可变内置对象是可散列的;可变容器(例如列表或字典)不是。默认情况下,作为用户定义类实例的对象是可散列的。它们都比较不相等(除了它们自己),它们的哈希值是从它们的id
派生的。
Pythonhash()函数
hash
函数返回对象的散列值(如果有的话)。散列值是整数。它们用于在字典查找期间快速比较字典键。对象可以实现__hash__
方法。
Python不可变内置函数是可哈希的
Python不可变内置函数(例如整数、字符串或元组)是可哈希的。
#!/usr/bin/python val = 100 print(val.__hash__()) print("falcon".__hash__()) print((1,).__hash__())
该示例打印了三个可哈希值的值:一个整数、一个字符串和一个元组。
Python自定义哈希示例I
默认情况下,Python自定义对象是可哈希的。他们的散列是从他们的Id派生的。
#!/usr/bin/python class User: def __init__(self, name, occupation): self.name = name self.occupation = occupation u1 = User('John Doe', 'gardener') u2 = User('John Doe', 'gardener') print('hash of user 1') print(hash(u1)) print('hash of user 2') print(hash(u2)) if (u1 == u2): print('same user') else: print('different users')
在示例中,我们有两个User
实例。
u1 = User('John Doe', 'gardener') u2 = User('John Doe', 'gardener')
我们有两个具有相同数据的实例。
print('hash of user 1') print(hash(u1))
hash
函数返回对象的哈希值。默认实现是从对象的Id派生的。
$ python custom_object.py hash of user 1 -9223371894419573195 hash of user 2 142435202673 different users
即使用户详细信息相同,比较也会产生不同的对象。为了改变它,我们需要实现__eq__
方法。
Python自定义哈希示例II
在第二个例子中,我们实现了一个自定义的__eq__
方法。
#!/usr/bin/python class User: def __init__(self, name, occupation): self.name = name self.occupation = occupation def __eq__(self, other): return self.name == other.name \ and self.occupation == other.occupation def __str__(self): return f'{self.name} {self.occupation}' u1 = User('John Doe', 'gardener') u2 = User('John Doe', 'gardener') if (u1 == u2): print('same user') print(f'{u1} == {u2}') else: print('different users') # users = {u1, u2} # print(len(users))
现在比较返回我们预期的输出;但是,我们不能将对象插入到Python集合中;它会导致TypeError:unhashabletype:'User'
。为了改变这一点,我们实现了__hash__
方法。
Python自定义哈希示例III
在第三个示例中,我们实现了__eq__
和__hash__
方法。
#!/usr/bin/python class User: def __init__(self, name, occupation): self.name = name self.occupation = occupation def __eq__(self, other): return self.name == other.name \ and self.occupation == other.occupation def __hash__(self): return hash((self.name, self.occupation)) def __str__(self): return f'{self.name} {self.occupation}' u1 = User('John Doe', 'gardener') u2 = User('John Doe', 'gardener') users = {u1, u2} print(len(users)) if (u1 == u2): print('same user') print(f'{u1} == {u2}') else: print('different users') print('------------------------------------') u1.occupation = 'programmer' users = {u1, u2} print(len(users)) if (u1 == u2): print('same user') print(f'{u1} == {u2}') else: print('different users')
该示例比较了两个具有__eq__
和__hash__
方法的自定义实现的对象。可以将这些对象插入到Python集合中,当属性稍后更改时,我们得到预期的输出。
def __hash__(self): return hash((self.name, self.occupation))
__hash__
函数的实现返回使用hash
函数从属性元组计算的哈希值。
$ python custom_object3.py 1 same user John Doe gardener == John Doe gardener ------------------------------------ 2 different users
Python@dataclass装饰器
从Python3.7开始,我们有了dataclass
装饰器,它会自动生成一些样板代码。
数据类装饰器有一个冻结参数(默认为False
)。如果指定,字段将被冻结(即只读)。如果eq
设置为True
,这是默认设置,那么__hash__
方法将被实现并且对象实例将是可散列的。
#!/usr/bin/python from dataclasses import dataclass @dataclass(frozen=True) class User: name: str occupation: str u1 = User('John Doe', 'gardener') u2 = User('John Doe', 'gardener') if (u1 == u2): print('same user') print(f'{u1} == {u2}') else: print('different users') users = {u1, u2} print(len(users))
该示例使用了@dataclass
装饰器。
$ python decorator.py same user User(name='John Doe', occupation='gardener') == User(name='John Doe', occupation='gardener') 1
在本教程中,我们介绍了Python中的散列。
列出所有Python教程。