python字典底层原理
python3.6以前字典是不能保证顺序的,3.6及其以后变为有序,dict主要遵循的是key的插入顺序
python3.6版本以前
'''存值时''':
初始化一个空的字典,cpython底层会初始化一个二维数组,数组8行3列;首先会对key值进行hash,得到当前状态下的hash值,这个hash值对8进行求余,得到余数,然后将要存的数据放到初始化数组的下标为该余数的这一行,第一列放hash值,第二列放指向key的指针,第三列放指向value的指针
'''取值时''':
key的hash值对8进行求余,在二维数组下标为余数的这一行就是所需的键值对,通过地址值获取到内存中数据
'''
由于hash值取余数后,余数可大可小,所以字典key并不是按照插入的顺序存放的
'''
# 1.当两个不同的key,经过hash,对8进行取余,可能最后的余数是一样的,就会使用开放寻址法,重新寻找一个新的位置
# 2.开放寻址的三种算法是线性探查,二次探查和双重散列;对于相邻的位置,选择的几率比较大
# 3.当字典的键值对数量超过数组长度的2/3时,数组会扩容,8行变16行,16行变32行,长度变了,原来的余数的位置就变了,此时就需要移动原来位置的数据,导致了插入效率变低
python3.6及以后版本
'''存值时'''
初始化一个空的字典,python单独生成了一个长度为8的一维数组indices,然后又生成了一个空的二维数组entries,对key进行hash,得到hash值,再对8进行求余,得到余数,再修改一维数组中对应下标为该余数的地方,第一次就改为0,0就是这个键值对在这个二维数组的行索引,才是二维数组只有一行数据,第一列为hash值,第二列为key所对应的指针,第三列则为value对应的指针
'''取值时'''
hash值对8进行求余,拿到一维数组中下标为该余数的索引,再去二维数组中找到下标为该索引的值,便能拿到键值对
'''
这种方式在遍历时,二维数组entries每一行数据都是有用的,不用再跳过,所以效率比较高
'''
二者内存占用的比较
'''假设在数组中,有效的数据都是三行'''
在3.6以前,每列8个字节,每行有三列,24个字节,共8行,所以占用的资源是8*24=192byte,而在3.6及其以后,indices数组占用8byte, entries数组占用3*24,所以共占用资源80byte