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教程。
