python可哈希数据类型_Python中的可哈希与不可哈希,对类做字典和集合去重

摘要:id,可变对象,不可变对象,hash

结论

可哈希的数据类型,即不可变的数据结构(数字类型(int,float,bool)字符串str、元组tuple、自定义类的对象(需要修改__eq__和__hash__方法))

不可哈希的数据类型,即可变的数据结构 (字典dict,列表list,集合set)

可哈希对象一定要是不可变对象

不可变类型,不同的值意味着不同的内存,相同的值存储在相同的内存,将的不可变对象理解成哈希表中的Key,将内存理解为经过哈希运算的哈希值Value,满足哈希表的性质

# 可哈希的不不可变对象

# 相同的值内存地址一致

a = 1

b = 1

c = 2

id(a) # 1399483872

id(b) # 1399483872

id(c) # 1399483904

对于可变对象,比如一个列表,更改列表的值,但是对象的地址本身是不变的,不同的列表对象映射到了相同的地址,不符合哈希值的特性的,出现了哈希运算里面的冲突。

# 不可哈希的可变对象

# 对一个list做append操作改变list的值但是id内存地址不变

a = [1, 2]

id(a) # 1962260509064,每次都会变

a.append(3)

id(a) # 1962260509064

c = [1, 2]

id(c) # 1962260454728

在set,dict结构中必须使用可哈希对象

dict通过key的内存地址找值,如果用可变对象比如list作为dict的key,每次新建的list虽然值一样但是内存地址id都会改变,导致实际找不到对应的value,Set使用的时HashSet同理也无法使用。

错误的写法,会报错TypeError: unhashable type: 'list'

set([[1, 2], [1, 2]])

{[1, 2]: 2}

正确的写法将可变对象转化为Tuple

set([(1, 2), (1, 2)])

{(1, 2): 2}

自定义对象是不可变对象,直接使用在set中或者dict中使用不会报错,但是依然无法使用

class Student:

def __init__(self, name, age):

self.name = name

self.age = age

def get_name(self):

return self.name

def get_age(self):

return self.age

调用set去重无效,a和c的id地址不一致

a = Student("gp", 12)

b = Student("gp", 21)

c = Student("gp", 12)

{<__main__.student at>,

<__main__.student at>,

<__main__.student at>}

调用dict无效,找不到key,新建的对象和a的id地址不一致

tmp = {a:1}

tmp[Student("gp", 12)]

TypeError: unhashable type: 'Student'

需要重写了类的__eq__和__hash__方法,前者可以使用==判断类是否相等,后者可以用来做dict的key和set去重

class Student:

def __init__(self, name, age):

self.name = name

self.age = age

def get_name(self):

return self.name

def get_age(self):

return self.age

def __eq__(self, other):

if all([self.name == other.name, self.age == other.age]):

return True

return False

def __hash__(self):

return hash(self.name + str(self.age))

a = Student("gp", 12)

b = Student("gp", 21)

c = Student("gp", 12)

a == c # True

a.__hash__() == c.__hash__() # True

id(a) == id(c) # False

set([a, b, c]) # {<__main__.student at>, <__main__.student at>}

tmp = {a:1}

tmp[Student("gp", 12)] # 1

for item in set([a, b, c]):

print(item.get_name())

# gp

# gp

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值