零基础学习Python第26课:认识字典

职场   2024-11-25 07:29   福建  

Hi,大家好,我是星光。

在Python中有两种最常用的基础数据结构,一个是你已耳熟能详的列表,另外一个是你即将耳熟能详的……字典。这字典不是新华字典、不是康熙字典、不是有道字典、不是英汉字典,不是我的生命里就没有不行这俩字的字典,而是又被称为散列表、哈希表、关联数组和映射的dictionary……

打个响指,认真脸,在Python中,字典是有一系列键值对组成的集合。就像我们上期学习过的集合一样,也具有可迭代性、可变性、唯一性和无序性的特点,但和集合所不同的是,它储存的不是单一元素,而是键值对[key-value pairs]。

什么是键值对呢?别说话,往下看。


1 丨 创建字典


1.1 dict()和{}

创建字典通常使用花括号{}或者dict()构造函数,以下代码均可以创建一个空字典。

d = {} d = dict() 

摊手,还记得上期教程中那句花括号无法创建空集合吧?原因就在于👆

以下代码使用花括号{}创建的字典包含了1个键值对,其中键key为'姓名',值value为'看见星光'。

d = {'姓名':'看见星光'} 


以下代码使用dict()函数创建的字典包含了2个键值对。

d = dict(    姓名 = '看见星光',    性别 = '男')


观察两段代码的不同之处,花括号的键值对语法格式为key:value,其中key为常量字符串时,需要使用引号包裹起来,而dict函数的键值对语法格式为key=value,key作为变量使用,不需要也不能使用引号包裹起来。


1.2 转换可迭代对象成字典

在实际应用中,经常需要将列表等可迭代对象直接转换为字典。

当一个列表是n行2列的结构时,可以直接使用dict()函数转换为字典。它默认第1列为键key,第2列为值value。以下代码将列表r转换为字典:{'姓名': '看见星光', '性别': '男'}

r = [['姓名','看见星光'],['性别','男']]d = dict(r)print(d)

如果有两个一维列表,其中一个为键key,另外一个为值value,可以先使用zip()函数将它们组合成键值对结构的迭代器,再使用dict()函数转换。

arkey = ['姓名','看见星光'] arValue = ['性别','男'] d = dict(zip(arkey,arValue)) 


1.3 字典推导式

使用字典推导式可以快速从可迭代对象中创建字典,它非常类似列表推导式,只是生成的结果不是列表,而是字典。语法格式如下:

{key_expression: value_expression for item in iterable}

语法中key_expression是生成键的表达式,value_expression是生成值的表达式,两者之间用冒号相连。

例如,以下代码有一个n行3列的列表r,需要将第1列作为key,最后一列作为value,生成一个字典:{'看见星光': 16, '王小睿': 15, '星辰': -16},参考代码如下:

r = [    ['看见星光','语文',16],    ['王小睿','语文',15],    ['星辰','语文',-16],]d = {s[0]:s[-1] for s in r}print(d)

再例如,有一个混合字符串构成的列表r,需要将其每个元素按短横杠拆分,将姓名作为key,性别转为value,生成字典:{'看见星光': '男', '王小睿': '女', '源哥': '女'}——这是本期的第一个练习题——个别学员朋友应该高标准严要求使用一行代码完成它,典型如星辰

r = [    '看见星光-男-语文-16',    '王小睿-女-数学-15',    '源哥-女-体育-16']


1.4 key的唯一性

需要注意的是字典的键key具有唯一性,只能使用不可变的数据类型,例如数字、字符串和元组等。值value则没有数据类型的限制,可以是不可变的数据类型,也可以是可变数据类型,例如列表、集合、字典等。

以下代码将key设置为列表,违反了键key的约束规则,会抛出代码异常:unhashable type: 'list'

d = {['看见星光'] : '男'}

以下代码中key'性别'出现了2次,违反了字典的key具有唯一性的原则,字典会使用后出现的键值对替代前面的键值对,最后返回字典:{'姓名': '星辰', '性别': '女'}

r = [        ['姓名','星辰'],        ['性别','男'],        ['性别','女']    ] d = dict(r) print(d)

……


2 丨 添加键值对

字典创建完成后,可以添加新的键值对,常用操作有以下几种方式。

2.1 添加单个键值对

往字典里添加新的元素,最简单最常用的方法是直接赋值。如果键已经存在,值会被更新;如果键不存在,会新增一个键值对。

d = {}d['姓名'] = '看见星光'print(d) # {'姓名': '看见星光'}d['姓名'] ='王小睿'print(d) # {'姓名': '王小睿'} 

以上代码中,先使用花括号创建了一个空字典。第2行代码新增一个键值对,key为姓名,value为看见星光。此时字典中不存在该key,直接新增该键值对,因此第3行代码打印结果为:{'姓名': '看见星光'}

第4行代码又新增一个键值对,key为姓名,value为王小睿。此时字典中存在相同的key姓名,于是更新对应的值。最终第5行代码打印字典的内容为:{'姓名': '王小睿'}。


2.2 添加多个键值对

如果需要往字典中批量添加多个键值对,可以使用update()方法。它接受一个字典或一个包含键值对结构的可迭代对象作为参数。

以下代码将一个n行两列结构的二维数组添加到字典中,其中第1列默认为key,第2列默认为value:

d = {'班级':'一班'}r = [        ['姓名','看见星光'],        ['性别','男']]d.update(r)print(d)

以下代码将一个字典合并到另一个字典中,相同的key会被后者更新,最后打印字典d1的内容为:{'班级': '二班', '姓名': '看见星光'}

d1 = {'班级':'一班'}d2 = {'姓名':'看见星光','班级':'二班'}d1.update(d2)print(d1)


3 丨 访问键值对



在其它系列教程中我们讲过,数据处理的过程,总结起来就是3个步骤,读取数据、计算数据、输出数据。字典计算数据的过程也不例外,将键值对添加到字典中,属于读取数据,数据计算完成后,还需要将其从字典中输出,也就是访问键值对。


3.1 访问单个键值对


...1)直接访问

键值对添加到字典中之后,可以通过键key快速访问对应的值value。以下代码中,第2行代码访问键'姓名'对应的value,结果为'看见星光'。

d = {'姓名':'看见星光','班级':'二班'}d['姓名'] #'看见星光' 

当字典中不存在指定的key时,代码会抛出异常:KeyError。

d = {'姓名':'看见星光','班级':'二班'}d['看见星光'] 

以上代码中第2行代码访问字典中不存在的键'看见星光',抛出异常结果如下图所示。


为了避免抛出异常,可以先使用成员运算符in判断字典中是否存在指定key,再访问key对应的value。

d = {'姓名':'看见星光','班级':'二班'}key = '看见星光'if key in d:    print(d[key])else:    print('没有这个人知道伐?') 

以上代码中第3行代码判断字典中是否存在指定key,条件成立则打印对应的value,否则打印字符串:没有这个人知道伐?

...2) get()方法

除了使用以上方法之外,也可以使用get()方法获取指定键的值。如果键不存在,该方法会返回第2参数指定的默认值,如果第2参数省略,则返回默认值 None。

d = {'姓名':'看见星光','班级':'二班'}print(d.get('看见星光')) print(d.get('看见星光','没有这个人知道伐'))print(d.get('姓名')) 

以上代码中第2~3行代码使用get()方法获取指定key对应的value,此时,字典中都不存在key:看见星光。其中第2行代码的get()方法没有指定第2参数,于是打印结果为None,第3行代码指定了第2参数,打印结果为:没有这个人知道伐?

第4行代码由于字典中存在指定key:姓名,则正常打印对应的value:看见星光。

...3) setdefault()方法

当访问的key在字典中可能不存在也可能存在,如果存在,则返回对应的value,如果不存在,你却需要将该key直接写入字典中,那么可以使用setdefault()方法。

setdefault() 方法获取指定键的值,如果键存在,则返回其值,如果键不存在,则插入该键并设置默认值。


d = {'看见星光':'男'} print(d.setdefault('看见星光''女')) print(d.setdefault('王小睿', '女')) print(d) 

以上代码中第1行代码创建了一个字典。

第2行代码使用setdefault() 方法获取key为'看见星光'的值。此时字典中已经存在该key,则不更新其值,并返回对应的value:男。

第3行代码使用setdefault() 方法获取key为'王小睿'的值。此时字典中不存在该key,则将键值对'王小睿':'女'写入字典,并返回key王小睿对应的值:女。

第4行代码打印字典,返回内容:{'看见星光': '男', '王小睿': '女'}

……

……打个响指,猜一猜,以下代码返回的结果是什么?为什么?

d = {'姓名':'看见星光','班级':'二班'} d[0]

...4) 一个简单的案例

字典这种通过键可以快速访问值的机制,非常适合于数据关联查询。

本期先举个简单的小栗子,更多数据关联查询的案例我们下期教程再详细讲解。

在本期案例工作簿中,有一个名称为'示例1'的工作表,内容如下图所示,A列是姓名,D列是成绩,现在需要查询F列人名对应的成绩。


先创建一个代码单元格,使用以下代码打开目标工作簿:

import xlwings as xwapp = xw.App(visible=True,add_book=False)path = r'工作簿的全路径'wb = app.books.open(path) 

再创建一个代码单元格,输入并运行以下代码

sht = wb.sheets['示例1'] # 选择工作表aData = sht.range('a2:d2').expand('down').value # 读取数据源a~d列aFind = sht.range('f2').expand('down').value # 读取需要查询的人名列d = {r[0]:r[3] for r in aData} # 构造字典,姓名为key,成绩为valueaRes = [[d.get(key,'查无此人')] for key in aFind] #使用字典查询结果sht.range('g2').value = aRes # 写入结果 

代码中第1~3行代码分别将数据源和需要查询的人名写入列表aData和aFind。

第4行代码使用字典推导式,遍历列表aData,将第1列的姓名作为key,第4列的成绩作为value。

第5行代码使用列表推导式,将姓名作为key查询对应的value成绩,如果字典中不存在指定人名,则返回字符串'查无此人'。

第6行代码将列表aRes写入目标单元格区域。

最后创建一个代码单元格,保存和关闭目标工作簿,退出创建的excel程序。

wb.save() # 保存wb.close() # 关闭app.quit() # 退出

……

这里留一道练习题(本期第2题),查询F列姓名对应的性别和成绩。


3.2 访问键值集

以上介绍的方法都是访问单个的键值对,字典也提供了直接返回键集、值集和键值集的方法。

...1)访问键集

keys()方法可以返回字典中所有键的视图。例如,以下代码返回结果:
dict_keys(['姓名', '班级'])

d = {'姓名':'看见星光','班级':'二班'} d.keys()

...2)访问值集

values()方法可以返回字典中所有值的视图。例如,以下代码返回结果:
dict_values(['看见星光', '二班'])

d = {'姓名':'看见星光','班级':'二班'} d.values()

...3)访问键值集

items()方法可以返回字典中所有键值对的视图。例如,以下代码返回结果:
dict_items([('姓名', '看见星光'), ('班级', '二班')])

d = {'姓名':'看见星光','班级':'二班'} d.items()

……

字典具有可迭代性,通过keys()/values()/itemes()等方法,可以快速迭代字典中的元素。

假设有一个字典,如下所示,keys是姓名,values是考试不及格的次数,现在需要筛选出不及格次数大于3次的,写入二维列表aRes。

d = {    '看见星光':4,    '源哥':5,    '王小睿':2,    '宗姐':2,    '掌门':3,    } 

参考解法1▼

aRes = [] for key in d.keys():    if d[key]>3 :         aRes.append([key,d[key]]) aRes 

第2行代码使用keys()方法遍历字典的键集,第3行代码访问key对应的value,如果value大于3,则第4行代码将key和value写入列表aRes。

将以上代码压缩成一行列表推导式,是为解法2▼

aRes = [[key,item] for key in d.keys() if (item:= d[key])>3] 

列表推导式的if子句执行筛选作用,其中使用了海象运算符,将d[key],也就是key对应的value,赋值变量item。

参考解法3▼

aRes = [[key,value] for key,value in d.items() if value>3] 

代码使用了items()方法直接获取字典的键值对视图。

摊手,以上代码各有优劣,都是你需要了解的,至于更详细的应用场景,后面两章字典应用经典案例中再见了。


4 丨修改键值对


字典具有可变性,可以原地修改字典中的元素,而不会创建一个新字典。在上面的案例中,我们介绍了如何往字典中添加键值对,这里再介绍一下如何修改或删除键值对。


4.1 更新键值对

当往字典中添加键值对时,如果键已经存在,值会被更新;如果键不存在,会新增一个键值对——利用这个特性,可以修改指定key对应的valule。

d = {}d['姓名'] = '看见星光' print(d)d['姓名'] ='王小睿' print(d)

以上代码中,先使用花括号创建了一个空字典。第2行代码新增一个键值对,key为姓名,value为看见星光。此时字典中不存在该key,直接新增该键值对。第4行代码又新增一个键值对,key为姓名,value为王小睿。此时字典中存在相同的key姓名,于是更新对应的值。最终第5行代码打印字典的内容为:{'姓名': '王小睿'}。


4.2 删除键值对

...1) clear()方法

使用clear()方法可以删除字典中所有的键值对,将其杀得一干二净,杀完之后字典还在,是一个空字典。

d = {'看见星光':'男'} d.clear()print(d) # 返回空字典{} 

...2) del语句

如果需要删除指定键值对,使用del语句是最直接的方法,但如果键不存在,它会抛出异常:KeyError

以下代码中第6行代码使用del 语句删除字典中指定key为'星辰'的键值对,第7行代码打印字典,结果显示'星辰'被成功干掉了。

d = {    '看见星光':'男人',    '星辰':'娃娃',    '随风小妞':'女人'}del d['星辰'] print(d) # 打印结果为 {'看见星光': '男人', '随风小妞': '女人'} 

需要注意的是,del是语句,不是函数,括号不是必须的。表达式为:del d['星辰']。当然,你也可以写成del (d['星辰']),只是看起来有些多此一举,这里的括号()不是函数,而是分组,表示d['星辰']是一个整体。

...3) pop()方法

如果键不存在,del语句会抛出异常:KeyError。如果此时你不希望抛出异常,可以先使用成员运算符in判断字典中是否存在指定key,又或者使用pop()方法。

pop() 方法用于移除并返回指定键的值。如果键不存在,它可以提供一个默认值,如果未提供默认值,则会抛出异常:KeyError。

d = {    '看见星光':'男人',    '星辰':'美男子',    '随风小妞':'女人'} print(d.pop('星辰'))print(d.pop('星辰','人已经不在了'))

以上代码中,第6行代码使用pop()方法移除key'星辰',并返回对应的value,打印结果为:'美男子'。

第7行代码再次使用pop()方法移除key'星辰',尝试返回对应的value。但此时字典中已经不存在该key了,于是返回pop()指定的默认值'人已经不在了'。

除了del和pop()方法之外,使用popitem() 方法可以随机移除并返回一个键值对。如果字典为空,会抛出 KeyError 异常——不常用,了解一下就好。

小贴士:

和上一章教程我们所学习的集合和再之前学习的列表都不同,字典并没有提供Remove()的方法。另外,你还需要注意区分字典和集合两者中pop()方法的不同。

……

一口气写到这儿,我倦了,倦的像一朵被风吹散的野花那就挥挥手,下期再见吧。嘿~!更多Python系统教程,欢迎点击文末「阅读原文」加入我的Python知识星球。

最后再留一个简单的练手题(本期第3题),在本期案例工作簿中,有一个名称为'示例2'的工作表,内容如下图所示,A~B两列存在重复的记录,需要删除重复项,模拟结果如D~E列所示。


……

……



🔽点击阅读原文

从0到1系统学习Python

Excel星球
微软全球最有价值专家(Excel MVP),上千篇原创图文和视频教程随学随用,随用随查,建议常用Excel的职场人关注。
 最新文章