Python 的对象天生拥有一些神奇的方法,它们总被双下划线所包围,它们是面向对象的 Python 的一切。它们是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了某一个魔法方法,那么这个方法就会在特殊的情况下自动被 Python 所调用。
功能
定义对象被 hash() 函数调用时的行为。
参数
self 表示对象自己。
返回值
一个整数,表示对象的哈希值。
示例
class MyTest(object):
def __init__(self):
self.name = '阿珍'
self.age = 18
def __hash__(self):
return hash(str(self))
sample = MyTest()
print(hash(sample))
python3 中,在 set,frozenset,dict 这三种数据结构中,都要求键值 key 是可 hash 的,因为要保证 key 的唯一性。
而__hash__实际上是返回一个 int 值,用来唯一标记这个对象。
一般讲解 hash 时,同时需要使用 eq。
可哈希的集合(hashed collections),需要集合的元素实现了__eq__和__hash__,而这两个方法可以比喻如下:
哈希集合就是很多个桶,但每个桶里面只能放一个球。
__hash__ 函数的作用就是找到桶的位置,到底是几号桶。
__eq__ 函数的作用就是当桶里面已经有一个球了,但又来了一个球,它声称它也应该装进这个桶里面(__hash__函数给它说了桶的位置),双方僵持不下,那就得用 __eq__ 函数来判断这两个球是不是相等的(equal),如果是判断是相等的,那么后来那个球就不应该放进桶里,哈希集合维持现状。
当可哈希集合(set,frozenset,dict)调用hash函数时,应该返回一个int值。唯一的要求就是,如果判断两个对象相等,那么他们的hash值也应该相等。当比较两个对象相等时是使用对象的成员来比较时,建议要把成员弄进元祖里,再得到这个元祖的hash值来比较。
当class没有定义__eq__()方法时,那么它也不应该定义__hash__()方法。如果它定义了__eq__()方法,却没有定义__hash__()方法,那么这个类的实例就不能在可哈希集合使用。如果一个类定义了一个可变对象(这里应该是指class的成员之一为可变对象),且implement了__eq__()方法,那么这个类就不应该implement __hash__()方法,因为可哈希对象的实现(implement )要求键值key的hash值是不变的(如果一个对象的hash值改变了,那么它会被放在错误的hash桶里)。
如下示例:
class Foo:
def __init__(self, item):
self.item = item
def __eq__(self, other):
print('使用了equal函数的对象的id', id(self))
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
else:
return False
def __hash__(self):
print('f' + str(self.item) + '使用了hash函数')
return hash(self.item)
f1 = Foo(1)
f2 = Foo(2)
f3 = Foo(3)
fset = set([f1, f2, f3])
print(fset)
print()
f = Foo(3)
fset.add(f)
print('f3的id:', id(f3))
print('f的id:', id(f))