开篇

img

以前在查阅纸质字典时,有一种音序查字法,可以根据汉字的拼音将查询范围缩小到几页纸中,然后逐页查找目标字。也就说,一个拼音可以对应多个汉字。

本期所讲的字典数据类型,也是根据某种东西(key)去查询另一种东西(value,但与上述过程稍微有些不同,至于不同之处嘛,我写在文中咯。

需要说明的是,字典中的许多方法名都类似于列表中的方法名,大家可以对比着学习,同时也不要搞混了哦~

让我们开始吧!

初识字典

字典用{}包裹,比如d={'name':'Bob','age':13,'gender':'male'}
便是一个字典:

img

观察上面的字典d,可以归纳出字典的基本结构

1
2
:`前面的被称为`key`(键),比如`'name'
:`后面的被称为`value`(值),比如`'Bob'

键和值合起来被称为一个键值对,比如'name':'Bob'

各个键值对之间用逗号,分隔开。

可以根据key来查找对应的value

1
2
3
>>> d={'name':'Bob','age':13,'gender':'male'}
>>> d['name']
'Bob'

创建字典

  • 方法**1.**使用{}创建一个字典

【栗子1】创建一个空字典

1
2
3
4
5
>>> z={}
>>> print(z)
{}
>>> print(type(z)) #type()用于查看变量所存内容的数据类型
<class 'dict'>

【栗子2】创建一个非空字典

1
2
3
>>> zz={'height':188,'age':3,'city':'Mars'}
>>> print(zz)
{'height': 188, 'age': 3, 'city': 'Mars'}
  • **方法2.**使用dict()创建一个字典

【栗子1】创建一个空字典

1
2
3
>>> x=dict()
>>> print(x)
{}

【栗子2】创建一个非空字典

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#1.使用`变量名=值`的方法
>>> a=dict(x=1,y=2,z=3)
>>> print(a){'x': 1, 'y': 2, 'z': 3}

#2.使用zip函数做一对一映射
>>> zi=zip(['x','y','z'],[1,2,3])
>>> print(list(zi))#查看zip函数作用后的结果
[('x', 1), ('y', 2), ('z', 3)]
>>> b=dict(zi)
>>> print(b)
{'x': 1, 'y': 2, 'z': 3}

#3.使用可迭代对象#列表内元素为可迭代对象:元组
>>> lis=[('x',1),('y',2),('z',3)]
>>> lis[('x', 1), ('y', 2), ('z', 3)]
>>> c=dict(lis)
>>> print(c)
{'x': 1, 'y': 2, 'z': 3}

#列表内元素为可迭代对象:列表
>>> lis=[['x',1],['y',2],['z',3]]
>>> lis[['x', 1], ['y', 2], ['z', 3]]
>>> d=dict(lis)
>>> print(d)
{'x': 1, 'y': 2, 'z': 3}
  • **方法3.**使用dict.fromkeys()创建字典,常用于字典的初始化
1
2
3
4
>>> key=['a','b','c']
>>> v=[1,2,3]
>>> dict.fromkeys(key,v)
{'a': [1, 2, 3], 'b': [1, 2, 3], 'c': [1, 2, 3]}

看,每个key对应的value都被初始化为[1,2,3]

注意,若想要拿到初始化之后的结果,必须将其赋值给一个新的变量,看这个栗子:

1
2
3
4
5
>>> d={}
>>> d.fromkeys(['a','b','c'],666)
{'a': 666, 'b': 666, 'c': 666}
>>> print(d)#依旧为空
{}

正确的做法是这样的:

1
2
3
4
>>> d={}
>>> dd=d.fromkeys(['a','b','c'],666)
>>> print(dd)
{'a': 666, 'b': 666, 'c': 666}

最后需要注意的是,若一个字典中有重复的key,则后面的key对应的value会将前面的key对应的value覆盖。看个栗子:

1
2
3
>>> d={'x':1,'y':2,'z':3,'x':4}
>>> d
{'x': 4, 'y': 2, 'z': 3}

字典的增删改查

和列表一样,字典也是可变数据类型,因此对字典的修改操作同样也是直接在原字典上进行。

1.增

可以直接使用dict[key]=value来添加一个新的键值对,举个栗子:

1
2
3
4
5
>>> z={'a':1,'b':2}
#添加一个键值对
>>> z['c']=3
>>> print(z)
{'a': 1, 'b': 2, 'c': 3}

还有一种update()方法,它可以将一个字典添加到另外一个字典中:

1
2
3
4
5
>>> d1={'a':1,'b':2,'c':3}
>>> d2={'d':4,'e':5}
>>> d1.update(d2)
>>> print(d1)
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

2.删

  • del

使用del可以删除某个键值对:

1
2
3
4
5
>>> z{'a': 1, 'b': 2, 'c': 3}
>>> del z
['a']
>>> print(z)
{'b': 2, 'c': 3}

也可以直接删除整个字典(不是变空,而是抹去):

1
2
3
4
5
>>> z
{'b': 2, 'c': 3}
>>> del z
>>> z
Traceback (most recent call last): File "<pyshell#110>", line 1, in <module> zNameError: name 'z' is not defined
  • pop()

删除某个键值对,并返回被删除键值对的value

1
2
3
4
5
>>> d={'x':1,'y':2}
>>> d.pop('x')
1
>>> print(d)
{'y': 2}
  • popitem()

每次运行都只能删除字典最末尾的元素,并且在字典变空时,若继续使用popitem()则会报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> s={'a':1,'b':2,'c':3}
>>> s.popitem()
('c', 3)
>>> print(s)
{'a': 1, 'b': 2}
>>> s.popitem()
('b', 2)
>>> print(s)
{'a': 1}
>>> s.popitem()
('a', 1)
>>> print(s){}
>>> s.popitem()
Traceback (most recent call last): File "<pyshell#144>", line 1, in <module> s.popitem()KeyError: 'popitem(): dictionary is empty'
  • clear()

用于清空整个字典,直接看栗子

1
2
3
4
5
6
>>> d=dict(zip(['a','b'],list(range(2))))
>>> print(d)
{'a': 0, 'b': 1}
>>> d.clear()#清空字典d
>>> print(d)
{}

3.改

如果你尝试向字典中增加键值对,而恰巧你所要添加的key已经存在于字典中了,那么此时你新添加key对应的value会覆盖原来的value,也就达到了修改的目的。

1
2
3
4
5
>>> d
{'a': 0, 'b': 1}
>>> d['a']='hello'#修改
>>> print(d)
{'a': 'hello', 'b': 1}

4.查

可以使用key来查询对应的value,就像查纸质字典一样,只不过在Python的字典中,一个key只能对应一个value,而纸质字典中一个key(拼音)可以对应多个value(具有相同拼音的汉字)。这便是开篇中提到的问题的答案。

1
2
3
4
>>> dd
{'a': 666, 'b': 666}
>>> dd['a']#查询key为'a'对应的value
666

但是注意:如果要查询的key并不存在,那么就会报错:

1
2
3
4
>>> dd
{'a': 666, 'b': 666}
>>> dd['c']
Traceback (most recent call last): File "<pyshell#241>", line 1, in <module> dd['c']KeyError: 'c'

那能不能在key不存在时不要报错呢?

Python的字典提供了get()方法,可以指定在查找失败时返回的值,而不再报错。

使用了get()方法后,当key不存在时,默认返回None,可以手动修改返回值。下面以栗子来说明具体的使用方法:

【栗子1】使用默认返回值None

1
2
3
4
5
>>> dd
{'a': 666, 'b': 666}#尝试查找key为'c'对应的value
>>> x=dd.get('c')#查找失败,返回默认值None
>>> print(x)
None

【栗子2】修改返回值

1
2
3
4
5
>>> dd
{'a': 666, 'b': 666}#尝试查找key为'c'对应的value
>>> x=dd.get('c',996)##查找失败,返回手动设定的数字996
>>> print(x)
996

字典的遍历方法

想要对字典进行遍历,首先想到的方法是:

先拿到key,然后用key去查询其对应的value。在外面套一层循环用来重复此操作,即可完成遍历。

需要知道的是:

通过dict.keys()可以拿到所有的key

1
通过``dict.values()`可拿到所有的`value

所以我们可以这样遍历:

1
2
3
d={'a':1,'b':2,'c':3}
for key in d.keys():
print(key,'=',d[key])

输出

1
2
3
a = 1
b = 2
c = 3

事实上,直接写成下面这样也可以得到相同的结果:

1
2
3
d={'a':1,'b':2,'c':3}
for key in d:
print(key,'=',d[key])

原因是:

在对字典进行遍历时,默认就是对所有的key进行遍历操作,所以这里的for key in d就等价于for key in d.keys()

另外,Python中的字典还提供了items()方法,用来获取键值对:

1
2
3
4
>>> d
{'a': 1, 'b': 2, 'c': 3}
>>> d.items()
dict_items([('a', 1), ('b', 2), ('c', 3)])

所以,我们也可以通过items()方法先获取键值对,然后对键值对进行遍历,从而也就完成了对整个字典的遍历操作。请看下面的栗子:

1
2
3
d={'a':1,'b':2,'c':3}
for i in d.items():
print(i[0],'=',i[1])

输出

1
2
3
a = 1
b = 2
c = 3

看,和上面的输出是一样的。

你甚至还可以做拆包(在下面会解释什么是拆包),直接同时获取keyvalue,遍历之,也可以得到上面的输出结果:

1
2
3
d={'a':1,'b':2,'c':3}
for k,v in d.items():
print(k,'=',v)

所谓拆包,就是将一个可迭代对象中的元素拆解成多个变量

以列表这个可迭代对象为例来说,我们将多个元素用列表存储是为了减少变量的个数,而拆包的目的正好相反,它是将一个列表中的多个元素分别用一个单独的变量来表示,从而变量的个数会增加。

举个栗子就清楚啦:

【栗子1】对字符串进行拆包

1
2
3
4
>>> s='abc'
>>> x,y,z=s #变量个数由1变3(增)
>>> print(x,y,z)
a b c

【栗子2】对列表进行拆包

1
2
3
4
>>> lis=[1,2]
>>> x,y=lis#变量个数由1变2(增)
>>> print(x,y)
1 2

现在你已经了解了什么是拆包,我们可以来解释一下for k,v in d.items()所做的事情了:

首先d.items()的内容为dict_items([('a', 1), ('b', 2), ('c', 3)]),这是一个可迭代对象,我们先来验证这一点:

1
2
3
>>> from collections.abc import Iterable
>>> isinstance(d.items(),Iterable)
True

返回值为True,是可迭代对象,验证完毕(ps:忘记验证方法的同学可以翻看列表那一期的内容)。

所以这段代码

1
2
3
d={'a':1,'b':2,'c':3}
for k,v in d.items():
print(k,'=',v)

所做事情的具体过程如下:

1
2
3
4
5
在做第1次循环时,k,v=d.items()等价于k,v=('a',1),于是k='a',v=1,打印输出'a'=1

在做第2次循环时,k,v=d.items()等价于k,v=('b',2),于是k='b',v=2,打印输出'b'=2

在做第3次循环时,k,v=d.items()等价于k,v=('c',3),于是k='c',v=3,打印输出'c'=3

字典推导式

和列表一样,字典也有推导式,其存在的原因同样是为了使得代码更加简洁。

问题:互换一个字典中的keyvalue。比如{'a':1,'b':2,'c':3}会变成{1:'a',2:'b',3:'c'}

若使用for循环,则代码风是这样的:

1
2
3
4
5
d={'a':1,'b':2,'c':3}
reversed_dict={}
for k,v in d.items():
reversed_dict[v]=k
print(reversed_dict)

输出

1
{1: 'a', 2: 'b', 3: 'c'}

但是如果使用了字典推导式,则代码风是这样子的:

1
2
3
d={'a':1,'b':2,'c':3}
reversed_dict={v:k for k,v in d.items()}
print(reversed_dict)

代码看起来是不是清爽很多?

当然,这并不是强制性的。如果你习惯了普通的循环操作,完全可以无视这种推导式的写法。不过我相信,当你熟悉推导式的写法之后会爱上它的简洁与优雅。


以上就是字典的基本用法,和列表一样,字典也是编程一大利器,需要好好掌握,大家加油!