【python-dict】dict的使用及实现原理
以下内容是针对: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的使用及实现原理的更多相关文章
- Python基础(dict 和 set) 字典和set
dict Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 举个例子,假设要根据同学的名字 ...
- python的dict,set,list,tuple应用详解
python的dict,set,list,tuple应用详解 本文深入剖析了python中dict,set,list,tuple应用及对应示例,有助于读者对其概念及原理的掌握.具体如下: 1.字典(d ...
- 第五章:深入Python的dict和set
第五章:深入Python的dict和set 课程:Python3高级核心技术 5.1 dict的abc继承关系 class Mapping(Collection): __slots__ = () &q ...
- Python中dict的特点、更新dict、遍历dict
dict的第一个特点是查找速度快,无论dict有10个元素还是10万个元素,查找速度都一样.而list的查找速度随着元素增加而逐渐下降. 不过dict的查找速度快不是没有代价的,dict的缺点是占用内 ...
- Python中dict详解
from:http://www.cnblogs.com/yangyongzhi/archive/2012/09/17/2688326.html Python中dict详解 python3.0以上,pr ...
- python之dict(或对象)与json之间的互相转化
在Python语言中,json数据与dict字典以及对象之间的转化,是必不可少的操作. 在Python中自带json库.通过import json导入. 在json模块有2个方法, loads():将 ...
- python 字典 dict 该注意的一些操作
在用python处理dict 的时候,有几个该注意的地方,这里跟大家提一下: 1)操作dict 时,尽量少产生新的列表对象.比如: 遍历dict的时候,如果用 dic = {"a" ...
- python字典dict的增、删、改、查操作
## python字典dict的增.删.改.查操作dict = {'age': 18, 'name': 'jin', 'sex': 'male', }#增# dict['heigh'] = 185 # ...
- Python 字典 dict() 函数
描述 Python 字典 dict() 函数用于创建一个新的字典,用法与 Pyhon 字典 update() 方法相似. 语法 dict() 函数函数语法: dict(key/value) 参数说明: ...
- Python中用dict统计列表中元素出现的次数
01 Python增加元素,不像其他语言使用现实的操作接口,只需要dict[1]=3,如果字典中不存在1,则直接新增元素键值对(1,3),如果存在则替换键1为3. if key in dict:判断出 ...
随机推荐
- NN 激活函数 待修改
Softmax 函数/算法 https://www.zhihu.com/question/23765351 RELU 激活函数及其他相关的函数 http://blog.csdn.net/u013146 ...
- 使用rpm 打包开发的postgres extension
环境准备 安装依赖包 rpmdevtools rpm-build yum install -y rpm-build rpmdevtools 初始化rpm pacakge 项目 主要是rpm 打包的 ...
- Linux cp命令详解
Linux cp命令 Linux cp命令主要用于复制文件或目录,将源文件复制至目标文件,或将多个源文件复制至目标目录 用法: cp [选项]... [-T] 源文件 目标文件 cp [选项]... ...
- pyhdfs安装
参考: http://blog.csdn.net/sinat_33741547/article/details/54428726 1.先更新pip,防止版本过低pip install --upgrad ...
- C# Interview Question 1
What is C#? What's the feature of C# language? Answer:
- SpringSecurity-RememberMeAuthenticationFilter的作用
启用remember-me功能,在配置文件中的http节点下添加: <remember-me remember-me-parameter="remember-me" reme ...
- WebService上传下载图片
WebService服务端 接受要上传的图片 public string UploadImg(byte[] fileBytes, int id) { try { string filePath = M ...
- 什么是BOM?,什么是DOM? BOM跟DOM之间的关系
什么是BOM? BOM是browser object model的缩写,简称浏览器对象模型.是用来获取或设置浏览器的属性.行为,例如:新建窗口.获取屏幕分辨率.浏览器版本号等. 比如 alert(); ...
- bootstrap的日期选择器
时间框偏移解决办法 首先导入js和css文件 <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js" ...
- C#各种小问题汇总不断更新
IIS Express Worker Process已停止工作-->管理员身份运行CMD 输入netsh winsock reset 回车OK 未能从程序集“System.ServiceMode ...