字典是“键值对”的无序可变序列,字典中的每个元素都是一个“键值对”,包含:“键对象”和“值对象”。可以通过”键对象“实现快速获取、删除和更新对应的”值对象“。
列表中通过“下标数字”找到对应的对象。字典中通过键值对找到对应的值对象。“键”是任意的不可变数据,如:整数,浮点数,字符串,元组。但是列表、字典、集合这些是可变对象,不能作为“键”。并且“键”不可重复。
值可以使任何数据,并且可以重复。
典型的定义字典方式:
a = {'name':'shengtudai','age':18,'job':'student'}
字典的创建
1.通过{} 、dict()来创建字典对象
>>> b = dict(name='shengtudai',age=8,job='student') >>> a = {'name':'shengtudai','age':18,'job':'student'} >>> a = dict([('name','shengudai'),('age',18)]) >>> c = {} >>> d = dict()
2.通过zip()创建字典对象
>>> k = ['name','age','job'] >>> v = ['shengtudai','18','student'] >>> d = dict(zip(k,v)) >>> d {'name': 'shengtudai', 'age': '18', 'job': 'student'}
3.通过fromkeys创建值为空的字典
>>> a = dict.fromkeys(['name','age','job']) >>> a {'name': None, 'age': None, 'job': None}
字典元素的访问
设定一个字典对象
a = {'name':'shengtudai','age':18,'job':'student'}
1.通过键获得值。若键不存在,则抛出异常
>>> a['name'] 'shengtudai' >>> a['qq'] Traceback (most recent call last): File "<pyshell#22>", line 1, in <module> a['qq'] KeyError: 'qq'
2.通过get()方法获得‘值’。推荐使用,指定键不存在,则返回null
>>> a.get('name') 'shengtudai' >>> a.get('qq') >>> a.get('sex','一个男人') '一个男人'
3.列出所有键值对
a.items() dict_items([('name', 'shengtudai'), ('age', 18), ('job', 'student')])
4.列出所有的键,列出所有的值
>>> a.keys() dict_keys(['name', 'age', 'job'])
>>> a.values() dict_values(['shengtudai', 18, 'student'])
5.len()键值对的个数
>>> len(a)
3
6.检测一个“键”是否在字典中
>>> "name" in a True
字典元素的添加、修改和删除
1.给字典新增键值对。如果键已经存在,则覆盖旧的键值对;若键不存在,则新增键值对
>>> a['address'] = '湖北公安' >>> a['age'] = 16 >>> a {'name': 'shengtudai', 'age': 16, 'job': 'student', 'address': '湖北公安'}
2.使用update()将新字典中所有键值对全部添加到旧字典上,如果key有重复,则直接覆盖
>>> a = {'name':'shengtudai','age':18,'job':'student'} >>> b = {'name':'kugua','money':'1000','sex':'男的'} >>> a.update(b) >>> a {'name': 'kugua', 'age': 18, 'job': 'student', 'money': '1000', 'sex': '男的'}
3.字典中元素的删除,可以使用del方法;或者clear()删除所有的键值对;pop()删除指定的键值对,并返回对应的"值对象"
>>> a = {'name':'shengtudai','age':18,'job':'student'} >>> del(a["name"]) >>> a {'age': 18, 'job': 'student'} >>> b = a.pop('age') >>> b 18
4.popitem():随机删除和返回该键值对。字典是“无序可变序列”,没有第一个和最后一个的概念;popitem()弹出随机的项
>>> a = {'name':'shengtudai','age':18,'job':'student'} >>> a.popitem() ('job', 'student') >>> a {'name': 'shengtudai', 'age': 18} >>> a.popitem() ('age', 18) >>> a {'name': 'shengtudai'} >>> a.popitem() ('name', 'shengtudai') >>> a {}
序列解包
序列解包可以用于元组、列表、字典。序列解包可以让我们方便的对多个变量赋值
>>> x,y,z = (20,30,10) >>> x 20 >>> y 30 >>> z 10 >>> type(x) <class 'int'> >>> (a,b,c) = (10,20,30) >>> a 10 >>> (a,b,c) = [10,20,30] >>> a 10
序列解包用于字典时,默认是对键进行操作;如果需要对键值对进行操作,则需要使用items();如果需要对值进行操作,则需要使用values()
>>> name,age,job = a >>> name 'name' >>> age 'age' >>> job 'job' >>> name,age,job = a.items() >>> name ('name', 'shengtudai') >>> name,age,job = a.values() >>> name 'shengtudai'
表格数据使用字典和列表存储,并实现访问
r1 = {'name':'高小一','age':18,'salary':30000,'city':'北京'} r2 = {'name':'高小二','age':19,'salary':20000,'city':'上海'} r3 = {'name':'高小五','age':20,'salary':10000,'city':'深圳'} tb = [r1,r2,r3] #获得第二行的人的薪资 print(tb[1].get('salary')) #打印列表中所有的薪资 for i in range(len(tb)): print(tb[i].get('salary')) #打印表的所有数据 for i in range(len(tb)): print(tb[i].get('name'),tb[i].get('age'),tb[i].get('salary'),tb[i].get('city'))
字典核心底层原理
字典对象的核心是散列表。散列表是一个稀疏数组(总是有空白元素的数组),数组的每个单元叫做bucket。每个 bucket有两部分︰一个是键对象的引用,一个是值对象的引
用。
由于,所有bucket结构和大小一致,我们可以通过偏移量来读取指定bucket.
将一个键值对放进字典的底层过程
a={}
a['name'] = 'shengtudai'
假设字典a对象创建完后,数组长度为8:
我们要把” name" =" gaoqi”这个键值对放到字典对象a中,首先第一步需要计算
由于数组长度为8,我们可以拿计算出的散列值的最右边3位数字作为偏移量,即"101”,十进制是数字5。我们查看偏移量5,对应的bucket是否为空。如果为空,则将键值对放进去。如果不为空,则依次取右边3位作为偏移量,即“100”,十进制是数学4。再查看偏移量为4的bucket是否为空。直到找到为空的bucket将键值对放进去。流程图如下:
根据键查找“键值对”的底层过程
我们明白了,一个键值对是如何存储到数组中的,根据键对象取到值对象,理解起来就简单了。
当我们调用a.get("name”),就是根据键“name”查找到“键值对”,从而找到值对象“gaoqi” .
第一步,我们仍然要计算“name”对象的散列值∶
和存储的底层流程算法一致,也是依次取散列值的不同位置的数字。假设数组长度为 8,我们可以拿计算出的散列值的最右边3位数字作为偏移量,即“101”,十进制是数字 5。我们查看偏移量5,对应的bucket是否为空。如果为空,则返回None。如果不为空, 则将这个bucket的键对象计算对应散列值,和我们的散列值进行比较,如果相等。则将对 应“值对象”返回。如果不相等,则再依次取其他几位数字,重新计算偏移量。依次取完活%, 仍然没有找到。则返回None。流程图如下:
用法总结∶
1.键必须可散列
(1)数字、字符串、元组,都是可散列的。
(2)自定义对象需要支持下面三点∶
①支持hash()函数
②支持通过_eq_(方法检测相等性。
③若a==b为真,则hash(a)==hash(b)也为真。
2.字典在内存中开销巨大,典型的空间换时间。
3.键查询速度很快
4.往字典里面添加新建可能导致扩容,导致散列表中键的次序变化。因此,不要在遍历字典的同时进行字典的修改。