Python-hash、__hash__、__eq__

1、函数介绍

__hash__
内建函数 hash() 调用的返回值,返回一个整数。如果定义这个方法该类的实例就可hash。

__eq__
对应==操作符,判断2个对象内容是否相等,返回bool值
定义了这个方法,如果不提供 __hash__ 方法,那么实例将不可hash了

2、__hash__示例

2.1、调用hash函数

print(hash(1))
print(hash('tom'))
print(hash(('tom',)))

2.2、__hash__使用

class A:
    def __init__(self, name):
        self.name = name

    def __hash__(self):
        return 1

    def __repr__(self):
        return self.name


a1 = A('tom')
a2 = A('tom')
print(a1, a2, hash(a1), hash(a2))
print([a1, a2])
print((a1, a2))
print({a1, a2})  # 去重了吗? 没有
print({a1, a1})  # 去重了吗?去重
print('-----')
# 元组
t1 = ('tom',)
t2 = ('tom',)
print(t1 is t2)
print(t1 == t2)
print({t1, t2})

# tom tom 1 1
# [tom, tom]
# (tom, tom)
# {tom, tom}
# {tom}
# -----
# True
# True
# {('tom',)}

3、__hash__和__eq__示例

3.1、简介

__hash__ 方法只是返回一个hash值作为set的key,但是 去重 ,还需要 __eq__ 来判断2个对象是否相等。
hash值相等,只是hash冲突,不能说明两个对象是相等的。
因此,一般来说实现 __hash__ 方法,要同时实现 __eq__ 方法。 去重 依赖 __eq__ 方法。
不可hash对象isinstance(p1, collections.Hashable)一定为False。

3.2、示例

class A:
    def __init__(self, name):
        self.name = name

    def __hash__(self):
        return 1

    def __repr__(self):
        return self.name

    def __eq__(self, other):
        return self.name == other.name

a1 = A('tom')
a2 = A('tom')
print({a1, a2})  # 去重了吗?,可以
print({A('jerry'), A('jerry')})  # 去重了吗?,可以

4、练习

4.1、需求

设计二维坐标类Point,使其成为可hash类型,并比较2个坐标的实例是否相等?

4.2、代码

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 "<Point {}:{}>".format(self.x, self.y)

p1 = Point(4, 5)
p2 = Point(4, 5)
print(hash(p1), hash(p2))
print(p1 is p2) # 对比id()
print(p1 == p2)
print({p1, p2})

# -1009709641759730766 -1009709641759730766
# False
# True
# {<Point 4:5>}

5、问题解答

5.1、list类实例为什么不可hash

源码中有一句 __hash__ = None,也就是如果调用 __hash__ ()相当于None(),一定报错。
所有类都继承object,而这个类是具有 __hash__ ()方法的,如果一个类不能被hash,就把__hash__ 设置为None。

5.2、functools.lru_cache使用到的functools._HashedSeq类继承自list,为什么可hash?

 _HashedSeq类提供了__hash__方法,这个方法实际上计算的是元组的hash值

 

posted @ 2023-07-20 18:03  小粉优化大师  阅读(373)  评论(0)    收藏  举报