前几天出去面试的时候,有被问到字典类型的数据在内存中是如何存储的,说实话从事开发工作3年来还真没有研究过这个问题,于是我也是看了几篇文章才学到的,那么我就来讲解一下这个问题

在这之前呢,我们说说什么是hash(摘要百度百科):

字典的底层原理

字典对象的核心其实是个散列表,而散列表是一个稀疏数组(不是每个位置都有值),每个单元叫做bucket,每个bucket有两部分:一个是键对象的引用,一个是值对象的引用,由于,所有bucket结构和大小一致,我们可以通过偏移量来指定bucket的位置

散列表如图:

python存储log python存储字典_散列表

将一对键值放入字典的过程:

先定义一个字典,再写入值

dict = {}
dict["age"] = "ming"

在执行第二行时,键name = 值ming放入字典中时,第一步就是计算name的散列值,python中可以用hash函数得到hash值,再用再将得到的值放入bin函数,返回int类型的二进制

print(bin(hash("age")))

# 结果:0b100010001110001000100010110000101101011110100010000101011001111

假设数组长度为10,我们取出计算出的散列值,最右边3位数作为偏移量,即111,十进制是数字7,我们查看偏移量为7对应的bucket的位置是否为空,如果为空,则将键值放进去,如果不为空,依次取右边3位作为偏移量001,十进制是数字1,再查看偏移量1的bucket是否为空,直到单元为空的bucket将键值放进去
以上就是字典的存储原理

字典的查询原理

dict['age'], dict.get('age')

散列值:0b100010001110001000100010110000101101011110100010000101011001111

查询就很简单了,第一步与存储一样,先计算键的散列值,取出后三位111,十进制为7的偏移量,找到对应的bucket的位置,查看是否为空,如果为空就返回None,不为空就获取键并计算键的散列值,计算后将刚计算的散列值与要查询的键的散列值比较,相同就返回对应bucket位置的value,不同就往前再取三位重新计算偏移量,依次取完后还是没有结果就返回None

 

可以做键的对象条件

  • 键必须可散列

       数字,字符串,元组,都是可散列的

  • 自定义对象做键的条件

       对象内部,有__hash__()和__eq__()方法