以下内容是针对:python源码剖析中的第五章——python中Dict对象 的读书笔记(针对书中讲到的内容进行了自己的整理,并且针对部分内容根据自己的需求进行了扩展)

一、Dict的用法

Dict的对象在使用到了所谓的关联关系的时候,就是通过key-value的形式,能够通过key值快速定位到某个value值;

Dict的相关操作如下:

class mydict(object):

def __init__(self):

self.d = {}

def fuzhi(self):

self.d = {'2':23, '3':'34'}

def fuzhi2(self):

self.d[1] = 1

self.d['str'] = 123

self.d['may'] = 234

self.d['may'] = 789

def delkey(self):

del(self.d[1])         #删除key时,key值必须存在于dict中,否则会报出 KeyError

self.d.pop('str')

def bianli(self):

for (k,v) in self.d.items():

print k, v

def getkeysandv(self):

print self.d.keys()              #获取当前dict中的所有key值

#获取某个元素值:

print self.d.get('345')         #若key不存在,则返回默认返回值None

print self.d.get('123', -1)   #若key不存在,则返回自定义的返回值-1

print self.d.get('may')    #若key值存在,则返回对应的value

def setkeyexcept(self):

self.d[[1,2,3]] =123       #可变对象不能作为key,会提示:TypeError: unhashable type: 'list' 的类似错误

二、Dict的存储实现原理

python中的dict对象也即PyDictObject对象,因为对搜索的效率要求很高,所以选择了散列表(hash table),因为在最优情况下,散列表能够提供O(1)的搜索效率

因此:这里就能想到在leetcode上面刷的题目中,很多通过list形式可以实现的,为了降低时间复杂度,可以用hash的方式,选择dict对象存储(当然具体问题要具体分析)

散列表的基本思想是:通过一定的函数将需要搜索的键值映射为一个整数,根据这个整数作为索引去访问某片连续的内存区域。用于映射的函数称为映射函数,映射所产生的值称为散列值(hash value)。散列函数对搜索效率有直接的决定性作用。在使用散列函数将不同的值可能映射到相同的散列值,这个时候就需要冲突解决(装载率大于2/3时,冲突的概率就会大大增加)

冲突解决在python中使用的是开放定址法,就是通过一个二次探测函数f,计算下一个位置,一直到找到下一个可用的位置为止,在这个过程中会到达多个位置,这些位置就形成了一个“冲突探测链”,这个冲突探测链在查找某个元素的时候起到重要作用,所以在删除某个位置上的元素,不能直接将这个位置的内容删除,如果删除的话,则导致后续依赖于这个位置的其他值就都无法寻找到了,所以只能进行“伪删除”(通过给元素设置状态,dummy态,表示没有存储具体的值但是还会用到的废弃态)

具体的PyDictObject对象中,会存在每一个元素,元素的定义是:

typedef struct{

Py_ssize_t me_hash;

PyObject *me_key;

PyObject *me_value;

}PyDictEntry;

每一个元素有三种状态,分别是:unused、active、dummy

状态

具体含义

unused

me_key=Null,me_value=Null

active

me_key!=Null,me_value!=Null

dummy

me_key=dummy,me_value=Null

PyDictObject对象的定义:

#define PyDict_MINSIZE 8

typedef struct _dictobject PyDictObject;

struct _dictobject{

PyObject_HEAD

Py_ssize_t ma_fill;  //元素个数: active+dummy

Py_ssize_t ma_used;  //元素个数: Active

Py_ssize_t ma_mask;

PyDictEntry *ma_table;

PyDictEntry *(*ma_lookup) (PyDictEntry *mp, PyObject *key, long hash);

PyDictEntry ma_smalltable[PyDict_MINSIZE];

}

其中各个字段的含义如下:ma_fill域中维护着从PyDictObject对象创建开始直到现在为止所有曾经及正在处于active态的entry个数;ma_used域中维护着当前正处于Active态的entry个数;ma_smalltable的PyDictEntry的数组,表示的是当创建一个PyDictObject对象的时候,至少创建PyDict_MINISIZE个entry被创建(这个数量在程序中定义是8个,这个数量是经过长期的经验所得来的值);ma_table是指向一块区域的,如果entry的数量不超过8个,那么这个指针就指向了ma_smalltable的地址,如果超过了8个,就需要申请一块大的内存,并且ma_table指向这块大的内存

三、Dict的操作实现原理(包括插入、删除、以及缓冲池等)

首先介绍:PyDictObject对象的元素搜索策略:

有两种搜索策略,分别是lookdict和lookdict_string,lookdict_string就是lookdict在对于PyStringObject进行搜索时的特殊形式,那么通用的搜索策略lookdict的主要逻辑是:

(1)对第一个entry的查找:

a)根据hash值获得entry的索引

b)若entry处于unused态,则搜索结束;若entry所指向的key与搜索的key相同,则搜索成功

c)若当前entry处于dummy态,则设置freeslot(这里的freeslot是可以返回作为下一个立即可用的地址来存储entry)

d)检查Active态的entry,若其key所指向的值与搜索的值相同,则搜索成功

(2)对剩余的探测链中的元素的遍历查找:

a)根据所采用的探测函数,获得探测链上的下一个待检查的entry

b)检查到一个unused态的entry,表明搜索失败:

如果freeslot不为空,则返回freeslot;否则返回unused态的entry

c)检查entry的key与所搜索的key的引用是否相同,相同则搜索成功,返回entry

d)检查entry的key与所搜索的key的值是否相同,相同则搜索成功,返回entry

e)遍历过程中,发现dummy态的entry,且freeslot未设置,则设置freeslot

接下来是:PyDictObject对象的元素插入与删除的策略:

需要首先用到搜索策略,搜索成功,则直接将值进行替换,搜索失败,返回unused态或dummy态的entry,设置key、value和hash值,并且根据目前插入的元素情况进行ma_table的大小的调整(调整的依据就是装载率,根据是否大于2/3来进行调整);删除也是类似,先计算hash值,然后搜索相应的entry,搜索成功,删除entry中维护的元素,将entry从Active态修改为dummy态

在PyDictObject的实现过程中,会用到缓冲池,在PyDictObject对象被销毁的时候,才开始接纳被缓冲的PyDictObject对象,定义的缓冲池可接纳的对象数量是80个,创建新PyDictObject对象的时候,如果缓冲池中有,则可以直接从缓冲池中取出使用

【python-dict】dict的使用及实现原理的更多相关文章

  1. Python基础(dict 和 set) 字典和set

    dict Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 举个例子,假设要根据同学的名字 ...

  2. python的dict,set,list,tuple应用详解

    python的dict,set,list,tuple应用详解 本文深入剖析了python中dict,set,list,tuple应用及对应示例,有助于读者对其概念及原理的掌握.具体如下: 1.字典(d ...

  3. 第五章:深入Python的dict和set

    第五章:深入Python的dict和set 课程:Python3高级核心技术 5.1 dict的abc继承关系 class Mapping(Collection): __slots__ = () &q ...

  4. Python中dict的特点、更新dict、遍历dict

    dict的第一个特点是查找速度快,无论dict有10个元素还是10万个元素,查找速度都一样.而list的查找速度随着元素增加而逐渐下降. 不过dict的查找速度快不是没有代价的,dict的缺点是占用内 ...

  5. Python中dict详解

    from:http://www.cnblogs.com/yangyongzhi/archive/2012/09/17/2688326.html Python中dict详解 python3.0以上,pr ...

  6. python之dict(或对象)与json之间的互相转化

    在Python语言中,json数据与dict字典以及对象之间的转化,是必不可少的操作. 在Python中自带json库.通过import json导入. 在json模块有2个方法, loads():将 ...

  7. python 字典 dict 该注意的一些操作

    在用python处理dict 的时候,有几个该注意的地方,这里跟大家提一下: 1)操作dict 时,尽量少产生新的列表对象.比如: 遍历dict的时候,如果用 dic = {"a" ...

  8. python字典dict的增、删、改、查操作

    ## python字典dict的增.删.改.查操作dict = {'age': 18, 'name': 'jin', 'sex': 'male', }#增# dict['heigh'] = 185 # ...

  9. Python 字典 dict() 函数

    描述 Python 字典 dict() 函数用于创建一个新的字典,用法与 Pyhon 字典 update() 方法相似. 语法 dict() 函数函数语法: dict(key/value) 参数说明: ...

  10. Python中用dict统计列表中元素出现的次数

    01 Python增加元素,不像其他语言使用现实的操作接口,只需要dict[1]=3,如果字典中不存在1,则直接新增元素键值对(1,3),如果存在则替换键1为3. if key in dict:判断出 ...

随机推荐

  1. zabbix_agent添加到系统服务启动(八)

    Centos6.5上安装了zabbix_agent后,需要把zabbix_agent添加到系统服务启动,要不然每次要一长串路径再启动,挺麻烦的. 步骤: 1)拷贝zabbix解压包里的zabbix_a ...

  2. [转]Servlet的学习之Filter过滤器技术

    本篇将讲诉Servlet中一项非常重要的技术,Filter过滤器技术.通过过滤器,可以对来自客户端的请求进行拦截,进行预处理或者对最终响应给客户端的数据进行处理后再输出. 要想使用Filter过滤器, ...

  3. xshell 显示中文

    xshell 可能无法正常显示中文,即使选择了utf-8编码也不生效. 1:输入:echo $LANG 显示:en_US.UTF-8 2.输入:export LANG=zh_CN.UTF-8 3. 输 ...

  4. DataTable.Select 处理关联表数据

    DataSet.Clone  会拷贝表结构,关联关系也会拷贝, 用Select 筛选后ImportRow 导入新的DataTable,然后处理关联DataTable DataSet ds2 = dsS ...

  5. 如何配置nginx负载均衡配置(轮询,权重,ip绑定)

    集群是为了解决单节点无法服务高并发的情况,在集群中nginx是如何分配将来自客户端的请求 转发给服务器的 负载均衡可以提高网站的吞吐量(接受和响应),减轻单台服务器的压力 负载均衡提供了三种策略:轮询 ...

  6. reids高可用(灾难备份-持久化)

    java缓存存放到内存之中,当服务器重启以后,内存的数据将丢失,而reids作为缓存,重启reids以后 数据是不是也会丢失,redis服务器重启以后数据也不会丢失,这个是redis提供了持久化的功能 ...

  7. Ext.NET Grid Group分组使用

    - 需要注意的是, 涉及到分页排序, 最好定义GroupDir 方向与分组方式相同. - 譬如工资表按照最新最前分页输出. 如果分组按照默认排序的话, 最就最前. - 界面呈现出2015年, 2016 ...

  8. 刘志梅 201771010115 《面向对象程序设计(java)》 第七周学习总结

    实验七 继承附加实验 实验时间 2018-10-11 1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: 即将类中的域标记为private,而方法标记为public.任何声明为priv ...

  9. LSTM/RNN中的Attention机制

    一.解决的问题 采用传统编码器-解码器结构的LSTM/RNN模型存在一个问题,不论输入长短都将其编码成一个固定长度的向量表示,这使模型对于长输入序列的学习效果很差(解码效果很差). 注意下图中,ax ...

  10. linux拷贝文件夹cp

    方法就是: cp -r dir dir 如果只是拷贝文件的话直接cp即可