为什么Python3.6字典变得有序了?

 

 

其实 在你看了笔者的文章之前,或许想过这样一个问题, 

  为什么列表是有顺序的呢?而字典不是?

    来看一下在内存中是怎样存储的就知道了:

      列表的存储是顺序存储,就像你上大学老师会点名的花名册一样,写的时候按顺序写,读的时候也是按顺序读的.

      而字典,在Python3.5之前,不能说无序,只能说不确定,时而有序是而无序.存储结构是hash表,是通过索引查找数据,所以存储的位置很随机,而读取是顺序读取得,因此写入和读取得顺序不同。他的旧结构就是这样的了

--+-------------------------------+
  | 哈希值 (hash)  键 (key)  值 (value)
--+-------------------------------+
0 |    hash0      key0    value0
--+-------------------------------+
1 |    hash1      key1    value1
--+-------------------------------+
2 |    hash2      key2    value2
--+-------------------------------+
. |           ...
__+_______________________________+

 

    那我们再来看一下结构

Indices
----------------------------------------------------
None | index0 | None | None | index2 | None | index1 ...
----------------------------------------------------

Entries
--------------------
hash0   key0  value0
---------------------
hash1   key1  value1
---------------------
hash2   key2  value2
---------------------
        ...
---------------------

新结构由 Indices(索引,数组实现) 和 Entries(实体,PyDictObject类型) 两种结构组成。

  • 当插入一个数据时,先计算数据对应的hash值并映射成 Indices 数组的一个下标,没有冲突的话就将另一个值 Entries_index(暂时这么叫吧) 填入Indices数组中下标对应的位置。并在Entries后面追加一行记录,类似 hash值, key值, value值 。如果冲突的话可以用基本的解决冲突的办法,这里不赘述了。

这种方法,字典 增删改查的时间复杂度 会有以前的O(1) 变为O(2),因为多了一步查找的过程。而且字典扩容和缩容时要按照Indices的顺序来保持字典始终有序。

但是至少有两个优化。

  • 字典占用的内存变小了。旧的字典总会预留大于 1/3的容量的hash位置,防止hash碰撞过多影响效率。现在则不必预留。
  • 字典有序了。

https://github.com/python/cpython/blob/3d75bd15ac/Include/dictobject.h#L23

posted @ 2019-12-25 16:09  koala_dz  阅读(802)  评论(0编辑  收藏  举报