去重本质原理
- __hash__值不等时,肯定不能去重
- __hash__值相等时,称hash冲突,冲突后得看__eq__是否相等,若相等则去重
实例hash工作原理
- 在__hash__返回必须为整数
- __hash__需自行定义hash的内容
任意实例hash为同一整数
- 说明hash返回值是由__hash__控制
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __hash__(self):
return 5000000
a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
运行结果:
5000000
5000000
不同实例hash值可能相等
- 说明hash算法决定实例hash值是否相等
- 举例:不同的坐标点,hash算法采用x+y的值,因此只要x+y相等,则hash值即相等
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __hash__(self):
return self.x + self.y
a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
运行结果:
3
3
正确hash算法策略
- 要避免hash冲突,首先要尽可能的算法要不一致
- 坐标点通过构建元组(x,y),对元组进行hash,因此只要x和y任意一个不相等,则hash值就不等
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __hash__(self):
return hash((self.x,self.y))
a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
运行结果:
3713081631934410656
3713082714465905806
验证集合__hash__不等去重与否
hash值不等时,肯定不能去重
在字典和集合,hash值相当于门牌号码,都不在一个房间里,肯定不能去重,去重的前提时,在一个房间里,是否为同一个值,如果时同一个值时,才能去重,不是同一个值时,不能去重,因此又引入__eq__判断是否相等的特殊属性。
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __hash__(self):
return hash((self.x,self.y))
def __repr__(self):
return "Point({},{})".format(self.x,self.y)
a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
print({a,b})
运行结果:
3713081631934410656
3713082714465905806
{Point(1,2), Point(2,1)}
hash值相等时,能否去重
- hash值相同时,说明在同一个房间内了,能否去重要根据__eq__是否为同一个数据了
- 如下实例,hash值相等,但是没有去重,因为不支持判断是否相等即eq属性
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __hash__(self):
return self.x+self.y
def __repr__(self):
return "Point({},{})".format(self.x,self.y)
a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
print({a,b})
运行结果:
3
3
{Point(2,1), Point(1,2)}
hash值相等,eq策略值不等不去重
- 当eq值不等时,说明同一个房间放着两个不同数据,当然不能去重
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __hash__(self):
return self.x+self.y
def __repr__(self):
return "Point({},{})".format(self.x,self.y)
def __eq__(self,other):
return self.x == other.y and self.y == other.y
a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
print({a,b})
运行结果:
3
3
{Point(2,1), Point(1,2)}
hash值相等,eq策略值相等时,去重
- 当eq策略值相等时,说明就是同一个值了
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __hash__(self):
return self.x+self.y
def __repr__(self):
return "Point({},{})".format(self.x,self.y)
def __eq__(self,other):
return self.x == other.y and self.y == other.x
a = Point(1,2)
b = Point(2,1)
print(hash(a))
print(hash(b))
print({a,b})
运行结果:
3
3
{Point(1,2)}
江湖案例
一山不容二虎,eq的策略是什么?头把交椅,若一个山上有两个都想坐头把交椅,则必须去重,只能留一个,相当于宋江火并王伦。若一个当头领,一个当军师,此时二者都可以留。因此要根据eq策略决定存留。