赞
踩
最近看代码遇到了一些自定义的类中实现了__hash__
函数,一直模模糊糊的知道__hash__
函数对类的实例做了哈希,使每个对象都有一个唯一值对应。但对于
这两个问题仍然无法解答,于是就搜罗了一下资料,并与诸君共享。
代码来源:https://github.com/lavis-nlp/spert/tree/master/spert(为方便演示进行了简化)。
class EntityType:
def __init__(self, index, short_name):
self._index = index
self._short_name = short_name
def __eq__(self, other):
if isinstance(other, EntityType):
return hash(self) == hash(other)
return False
def __hash__(self):
print(f'{self._index} 对应的哈希值:{hash((self._index, self._short_name))}')
return hash((self._index, self._short_name))
该类是一个关于“实体”的类(实体是什么不重要,就想象成是关于猫的类,猫猫有一个编号和名字)。
代码里不仅实现了__hash__
,还实现了__eq__
。先暂且记住两个是需要同时实现的。
下面使用这个类声明两个对象,
e3 = EntityType(3, 'c')
e4 = EntityType(3, 'c')
if e3 == e4:
print('Same')
else:
print('Different')
输出:
3 对应的哈希值:-4381402341035294393
3 对应的哈希值:-4381402341035294393
Same
在Python中自定义的对象默认是可hash 的,并且默认hash 值是通过id 获得,这个id 指的是存储的地址,但从地址得到的hash 值一般不符合我们的要求,我们更希望是通过对具体数据进行hash ,然后得到hash 值。
所以在上面的例子中, hash了由self._index 和 self._short_name组成的元组,这样的好处是如果有两个对象的值相同,那么可以通过比较hash 值快速判断。而用于判断的函数就是__eq__
,这就相当于C++中的操作符重载,__eq__
相当于重载了==
。
综上,可以总结出,我们重写_hash__
(记住这里是重写,因为默认是可hash的,所以本身会有该函数)的场景就是,如果我们新创建的类,需要保证值不重复性就可以进行进行重写,另外不要忘记还要重写__eq__
函数。
另外:有些文章提到了【可变对象和不可变对象】与【不可哈希和可哈希】的关系,提到了list set dict是可变对象,元素会有增有减,“所以” list set dict是不可hash的,和其中的元素是否可hash没有关系。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。