python教程(七)·字典

本文介绍本系列教程最后一个数据结构——字典


在现实生活中,查英语字典的时候,我们通常根据单词来查找意思。而python中的字典也是类似的,根据特定的 “键”(单词)来查找 “值”(意思)。

字典的基本使用

下面以电话簿为例,我们的电话簿记录的是电话号码。当要查找电话号码时,我们根据人名来查找其电话号码,所以人名就是字典的键,电话号码就是字典的值。假设有下面这样的人名和电话号码的电话簿:

1
2
3
4
5
人名=>电话
Aganzo=>1230
Jack=>0221
Lee=>1354
Emilie=>2479

创建字典

现在我们来创建一个字典来表示这个电话簿:

1
2
3
4
>>> phonebook={'Aganzo':'1230', 'Jack':'0221', 'Lee':'1354', 'Emilie':'2479'}
>>> phonebook
{'Aganzo': '1230', 'Jack': '0221', 'Lee': '1354', 'Emilie': '2479'}
>>>

从上面可以看出,创建字典的基本格式为{ 键1:值1, 键2:值2, 键3:值3 ...}。除了这种方法,我们还可以通过dict函数传递关键字参数来创建字典,像下面这样:

1
2
3
4
>>> phonebook = dict(Aganzo='1230', Jack='0221', Lee='1354', Emilie='2479') # 关键字参数就是字典的键,参数值就是字典的值
>>> phonebook
{'Aganzo': '1230', 'Jack': '0221', 'Lee': '1354', 'Emilie': '2479'}
>>>

我们常用第一种方式创建字典,第二种方式比较少用,而且第二种方式有一个缺点:因为关键字参数会变为字典的键,所以键必须符合参数的命名规则(字母或下划线_开头,其后是数字、字母或下划线)。

补充:创建空字典有两种方法,一种是直接使用{};另一种是调用dict函数时,参数留空,即dict();像键:值这样的东西叫做字典的 “项”

字典基本操作

字典的基本操作有:

先来说“查”:我们可以通过名字来查找电话簿中的电话号码,在字典中类似这样,通过“键”来查“值”,基本格式为字典[键]

1
2
3
4
5
6
7
8
9
>>> phonebook['Aganzo']
'1230'
>>> phonebook['Jack']
'0221'
>>> phonebook['Lily']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Lily'
>>>

从上面的代码可以看出,我们的“电话簿”中不存在Lily的电话号码,可知,当字典中不存在要查的元素时,python会提示报错。我们可以在查之前确认字典中是否有对应的项,使用成员运算符in

1
2
3
4
5
>>> 'Lily' in phonebook # 不存在
False
>>> 'Jack' in phonebook # 存在
True
>>>

或者查看“电话簿”中所有人的电话号码:

1
2
3
4
5
6
7
8
>>> for key in phonebook:
... print('%s=>%s' % (key, phonebook[key]))
...
Aganzo=>1230
Jack=>0221
Lee=>1354
Emilie=>2479
>>>


再来说“改”:此时得知Lee更换了电话号码为112233,需要对电话簿进行更改,使用如下代码:

1
2
3
4
>>> phonebook['Lee'] = '112233'
>>> phonebook
{'Aganzo': '1230', 'Jack': '0221', 'Lee': '112233', 'Emilie': '2479'}
>>>


再到“增”:假设新认识了一位朋友Zieg,得到了朋友的电话号码为123456,需要在“电话簿”中新增一项,和“改”操作一样,使用赋值运算符=

1
2
3
4
>>> phonebook['Zieg'] = '123456'
>>> phonebook
{'Aganzo': '1230', 'Jack': '0221', 'Lee': '112233', 'Emilie': '2479', 'Zieg': '123456'}
>>>


最后说“删”:朋友Jack与你绝交了(世事无常╮(╯▽╰)╭),你决定删除他的联系方式,此时你狠心地运行了下面的代码:

1
2
3
4
>>> del phonebook['Jack']
>>> phonebook
{'Aganzo': '1230', 'Lee': '112233', 'Emilie': '2479', 'Zieg': '123456'}
>>>

“电话簿”中再也没有了Jack的电话号码……

小结

好了,一个简单的示例过后,相信大家能理解字典的使用方法了,让我们来一个小小的总结:

创建字典的方法:

  • 通过花括号创建 x = {键1:值1, 键2:值2, 键3:值3 ...}
  • 通过dict函数创建 x = dict(key1=value1, key2=value2, key3=value3 ...)
  • 创建空字典可以使用 x = {}x = dict()

字典的基本操作:

  • 增:x['abc'] = 123 (键’abc’不存在)
  • 删:del x['abc']
  • 改:x['abc] += 1x['abc'] = 2x['abc'] *= 10……(键’abc’存在)
  • 查:result = x['abc']print(x['abc'])……(键’abc’存在)

补充:字典的用法和列表类似,只不过列表索引元素的时候使用的是数字作键,而字典大多数时候使用字符串索引元素。


关于字典的键,还有一点是要说清楚的:前面我们使用字典的时候都是使用了字符串类型的键,可我没有说字典的键只能是字符串!

实际上,字典的键可以是任意的不可变类型,如:字符串(最常用)、元组、浮点数、整数。


字典方法

字典也是对象,和列表一样,字典也提供了一些实用的方法,下面是介绍

clear

clear方法用于清空字典中的所有项:

1
2
3
4
5
6
7
>>> d = {'name':'feather', 'age':18}
>>> d
{'name': 'feather', 'age': 18}
>>> d.clear()
>>> d
{}
>>>

这个方法是原地的操作,意思就是操作对象是在字典本身,这和直接将变量赋值为空字典是不一样的,从下面的例子可以看出:

1
2
3
4
5
6
7
8
>>> x = {'a':1}
>>> y = x # y变量引用的字典和x变量引用的是同一个字典
>>> x = {} # 将x变量引用改为另一个字典,这个字典是空字典
>>> x
{}
>>> y # y变量引用的字典没有被改变
{'a': 1}
>>>

copy

copy方法用于返回一个新字典,这个新字典和原来的字典拥有相同的项:

1
2
3
4
5
6
7
8
9
>>> x = {'name':'feather', 'blog':['https://blog.csdn.net/lonely_feather', 'https://featherl.gitee.io/']}
>>> y = x.copy()
>>> y['name'] = 'Lee'
>>> y['blog'].append('https://www.cnblogs.com/featherl/')
>>> x
{'name': 'feather', 'blog': ['https://blog.csdn.net/lonely_feather', 'https://featherl.gitee.io/', 'https://www.cnblogs.com/featherl/']}
>>> y
{'name': 'Lee', 'blog': ['https://blog.csdn.net/lonely_feather', 'https://featherl.gitee.io/', 'https://www.cnblogs.com/featherl/']}
>>>

可以看到,y字典是从x复制而来的,所以改变y字典的键为’name’的项的时候并不影响x字典,要注意的是,y['blog'].append('https://www.cnblogs.com/featherl/')这句代码不属于修改y字典,这是修改y字典的键为’blog’的项引用的列表,而y字典和x字典的’blog’项引用的是同一个列表(因为y字典的项是从x字典中复制而来的),所以修改这个列表的时候,在x和y两个字典上都可以看到效果。

这种问题是因为copy方法是“浅复制”,copy方法仅仅把相同的值存储到了一个新的字典里,要想避免这种问题,需要使用“深复制”,可以使用copy模块的deepcopy函数来实现:

1
2
3
4
5
6
7
8
9
>>> from copy import deepcopy
>>> x = {'list':[1,2,3]}
>>> y = deepcopy(x)
>>> y['list'].append(4)
>>> x
{'list': [1, 2, 3]}
>>> y
{'list': [1, 2, 3, 4]}
>>>

fromkeys

fromkeys方法用给定的键创建新字典,每个键对应的默认值都为None:

1
2
3
4
>>> {}.fromkeys(['name'])
{'name': None}
>>> dict.fromkeys(['name', 'age'])
{'name': None, 'age': None}

上面代码的第一个例子中,我们创建了一个空字典,然后使用这个空字典的fromkeys方法创建了一个新字典,第二个例子中,我们直接使用dict这个类(实际上dict不是函数,是一个“类”)的fromkeys方法创建新字典。

我们还可以自己设置默认值:

1
2
>>> dict.fromkeys(['name', 'age'], '???')
{'name': '???', 'age': '???'}

get

get方法使用给定的键访问字典中的项,不过,如果字典中不存在该项时,get方法返回默认值None,而不是报错:

1
2
3
4
5
6
>>> x = {'name':'Lee'}
>>> x.get('age')
>>> print(x.get('name'))
Lee
>>> print(x.get('age'))
None

同样的,这个默认值也是可以自己设定的:

1
2
3
>>> x = {'name':'Lee'}
>>> x.get('age', '???')
'???'

update

update方法将一个新字典合并到当前字典,当存在相同的键,用新字典的值进行覆盖:

1
2
3
4
5
6
>>> x = {'name':'Lee'}
>>> x = {'name':'Lee', 'blog':'https://featherl.gitee.io'}
>>> y = {'name':'feather', 'age':18}
>>> x.update(y)
>>> x
{'name': 'feather', 'blog': 'https://featherl.gitee.io', 'age': 18}

pop

pop方法用来返回指定键的项,并将该项从字典中移除:

1
2
3
4
5
>>> x = {1:1, 2:2, 3:3}
>>> x.pop(1)
1
>>> x
{2: 2, 3: 3}

上面的例子同时也证明了字典的键不一定是字符串。

popitem

popitem方法随机挑选一个项返回,并删除这个项。字典不同于列表,字典的项是没有顺序,不同的机器或者不同版本的python,其字典存储项的顺序可能是不一样的,故popitem方法具体处理哪一项是没法预测的。

使用举例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> x = {1:1, 2:2, 3:3}
>>> x.pop
x.pop( x.popitem(
>>> help(x.popitem)

>>> x.popitem()
(3, 3)
>>> x.popitem()
(2, 2)
>>> x.popitem()
(1, 1)
>>> x.popitem()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'popitem(): dictionary is empty'

当字典为空的时候,该方法抛出错误。

items

items方法返回字典的所有的项,每个项为一个形式为(key, value)的元组,返回的类型是一种类似列表的类型,可以使用for循环迭代,但是没有列表的方法,最好先使用list转换成列表:

1
2
3
4
5
>>> x = {'name':'Lee', 'age':18}
>>> x.items()
dict_items([('name', 'Lee'), ('age', 18)])
>>> list(x.items()) # 转换成列表
[('name', 'Lee'), ('age', 18)]

注意:在python2中此方法还有后面的keys、values方法返回的就是列表类型,不过我们学的是python3,要注意区分。

类似items的方法还有:

  • keys方法返回字典的所有的键(类似列表的类型)
  • values方法返回字典的所有的值(类似列表的类型)

到此为止,本系列教程的python数据结构已经介绍完了,在本系列教程只是介绍了python中如何使用常用数据结构,并没有讲实现原理。而数据结构在计算机领域是不可或缺的,希望对数据结构了解甚少的读者可以认真学习一下数据结构的相关知识。

等学习完文件操作后,我们将用一个小项目实践一下(其实忽略文件操作,目前学到的知识还是可以做很多东西的),敬请期待! ( ̄︶ ̄)↗