抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

image-20210517200120122

第八章 数据类型:dict字典

8.1 初识字典

8.1.1 为何需要字典?

任务一:为何需要字典?

知识点:

字典也是Python提供的一种常用的容器类型的数据结构,它用于存放一组具有映射关系的数据

例如,个人信息,姓名:小明,年龄:18,性别:男,身高:1.75

这组数据看上去像两个列表,但这两个列表的元素之间有一定的关联关系

如果单纯使用两个列表来保存这组数据,则无法记录两组数据之间的关联关系

为了保存具有映射关系的数据,Python提供了字典,字典相当于保存了两组数据,其中一组数据是关键数据,被称为 key;另一组数据可通过key来访问,被称为value

1
2
3
4
5
6
7
# 希望将key和val成对绑定
key = ['name', 'age', 'gender', 'height']
val = ["小明", 18, True, 1.75]
print(key, val)

# 无法直接绑定信息,只能通过索引隐式的绑定
print(f'{key[0]}:{val[0]}')

任务二:字典的定义

知识点:

字典(dictionary)是 除列表以外Python 之中 最灵活的数据类型

字典用来存储多个数据,是一种无序的可变容器模型,且可存储任意类型对象。字典可以存储用于描述某个物体 的额外信息

字典与列表区别:

列表有序的对象集合

字典无序的对象集合

知识点:定义字典

语法:d = {key1:value1, key2:value2}

字典使用**{}** 来定义和标识

字典使用键值对(key-value)存储数据,键值对之间使用 , 分隔

键 key 是索引,必须是唯一

值 value 是数据,可以取任何数据类型

每个键值对中的用冒号**:**分割

可以取任何数据类型,但 只能使用字符串数字元组

dict为字典类型,避免使用dict作为变量名

任务三:解析字典数据结构

1
2
3
4
5
6
7
8
9
10
# 创建个人信息字典
info = {"name": "小明",
"age": 18,
"gender": True,
"height": 1.75}

print(type(info), info)

# 可以使用key作为索引访问字典元素
print(info['height'])

任务四:字典变量的适用场景

知识点:

字典一般用于描述某个物体属性信息

字典的key通常为字符串,用于描述value

字典是无序的数据集合

8.1.2 字典的创建

常用的有两种字典创建方式,一种是使用**{}创建字典;另外种是通过dict()**函数

任务一:使用{}创建字典

知识点:

d = {key1:value1, key2:value2},将多个key-value对作为字典元素,放在**{}**中创建字典

**d = {}**为创建空字典

使用**{}方式创建字典,只能手动添加key-value**对

1
2
3
4
5
6
7
8
vegetables = {'celery': 1.58, 'brocoli': 1.29, 'lettuce': 2.19}
print(vegetables)

cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
print(cars)

empty_dict = {}
print(empty_dict)

任务二:使用dict()创建字典

知识点:

在使用dict()函数创建字典时,可以传入嵌套的列表或元组参数作为key-value

每个列表的元素为由两个元素构成的子列表或元组,作为字典的一个key-value

**dict()**函数可以从已有的数据(列表或元组)创建字典

1
2
3
4
# 创建包含3组key-value对的字典
vegetables = [('celery', 1.58), ('brocoli', 1.29), ('lettuce', 2.19)]
dict3 = dict(vegetables)
print(dict3)
1
2
3
4
# 创建包含3组key-value对的字典
cars = [['BMW', 8.5], ['BENS', 8.3], ['AUDI', 7.9]]
dict4 = dict(cars)
print(dict4)

知识点:如果不为**dict()**函数传入任何参数,则代表创建一个空的字典

1
2
3
# 创建空的字典
dict5 = dict()
print(dict5)

知识点:

通过为dict()函数指定关键字参数创建字典,此时字典的key不允许使用表达式

dict()函数会关键字参数作为字典的key,不需要将它们写成字符串形式,dict()函数会自动将它们转化为字符串格式的key

1
2
3
# 直接写spinach、cabbage而非字符串
dict6 = dict(spinach = 1.39, cabbage = 2.59)
print(dict6)

任务三:三种括号对应的数据类型

知识点(总结):三种括号对应的数据类型

列表list的标识为**[];元组tuple的标识为();字典dict的标识为{}**

相对于列表和元组用数字来索引元素,字典可以使用自定义有意义key来索引元素

1
2
3
4
5
6
7
8
9
# 空列表、元组、字典创建
list_val = []
print(type(list_val), list_val)

tuple_val = ()
print(type(tuple_val), tuple_val)

dict_val = {}
print(type(dict_val), dict_val)
1
2
3
4
5
6
7
8
list_val = [1, 2, 3, 4]
print(type(list_val), list_val)

tuple_val = (1, 2, 3, 4)
print(type(tuple_val), tuple_val)

dict_val = {'a': 1, 'b': 2, 'c': 4}
print(type(dict_val), dict_val)
1
2
3
4
# 列表和元组用数字来索引元素
# 字典使用key来索引元素
print(list_val[0], tuple_val[0])
print(dict_val['a'])

8.2 深入字典

8.2.1 字典元素:键值对

任务一:字典元素是key-value键值对

知识点:d = {key1:value1, key2:value2}

字典的元素是键值对(key-value)

每个key-value用冒号**:分割,每对之间用逗号,分割,整个字典包括在大括号{}**中

每个key都有与之关联的value,可以通过key来访问(索引)相应的value。例如,value = d[key]

字典的key是唯一,value可以重复

知识点:

通过字典的key可以索引value,也可以对value进行修改

例如,访问元素val = d[key1];修改元素d[key1] = new_value

列表、元组是有序的,它的索引是从0开始的序号;字典是无序的,它的索引是key

1
2
3
4
5
6
7
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
# 通过key来访问value
print(cars['BMW'])

# 通过key修改value值
cars['BMW'] = 10.1
print(cars)

任务二:字典特性(key是唯一的)

知识点:

字典的key必须是唯一的,但value可以重复

如果字典中存在重复key,那么后面一个keyvalue覆盖前个keyvalue

字典的key是唯一的。例如,两组相同的key:’height’: 1.8和**’height’: 80。那么,‘height’value**会被80覆盖

1
2
3
# key是唯一的
info = {'height': 1.8, 'height': 80, 'age': 20, 'sex': 0}
print(type(info), info)

不同的key可以使用相同的value。例如,**’height’: 1.8‘weight’: 1.8**,它们相互不影响

1
2
3
# value可以重复
info = {'height': 1.8, 'weight': 1.8, 'age': 20, 'sex': 0}
print(type(info), info)

任务三:字典特性(key必须是不可变类型)

知识点:keyvalue的类型要求

key:必须是不可变类型,包括数值类型、字符串和元组tuple

value:可以是任意类型的对象

建议key使用有意义的字符串。key的目的是为了方便地索引字典元素

知识点(注意):

元组是不可变类型,因此元组tuple可以作为字典的key

列表是可变类型,因此列表list不能作为字典的key,否则会引起TypeError

下面例子中,第1个元素的key为字符串,第2个为整形,第3个为浮点数,第4个元组

1
2
3
# 不同类型的key
info = {'height': 1.8, 80: 'weight', 3.1: {20, 11}, (0, ): 'sex'}
print(type(info), info)
1
2
3
# 可变类型的列表不能作为key
info = {'height': 1.8, [1,1]: 'weight', 3.1: {20, 11}, (0, ): 'sex'}
print(type(info), info)

8.2.2 字典元素操作

任务一:字典基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
xiaoming_dict = {"name": "小明"}

# 1. 取值
print(xiaoming_dict["name"])
# 在取值的时候,如果指定的key不存在,程序会报错!
# print(xiaoming_dict["name123"])

# 2. 增加/修改
# 如果key不存在,会新增键值对
xiaoming_dict["age"] = 18
# 如果key存在,会修改已经存在的键值对
xiaoming_dict["name"] = "小小明"

# 3. 删除
xiaoming_dict.pop("name")
# 在删除指定键值对的时候,如果指定的key不存在,程序会报错!
# xiaoming_dict.pop("name123")

print(xiaoming_dict)

任务二:添加新元素

知识点:为字典添加新的key-value,只需通过对不存在key赋值即可

语法:d[key]=value

如果key存在,那么修改key对应的value

如果key不存在,那么对dict添加新的key-value元素

1
2
3
4
5
6
7
8
9
10
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
print(cars)

# 不存在的key添加新元素
cars['Ford'] = 10.1
print(cars)

# 存在的key修改value
cars['BMW'] = 9.1
print(cars)

任务三:访问不存在的字典元素

知识点:如果使用不存在的key来访问dict中元素,那么就会引发异常KeyError

1
2
3
4
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
print(cars)

print(cars['Ferraris'])

任务四:删除字典元素和整个字典

知识点:使用del可以删除整个字典或者是字典中的某个元素,永远消失

删除单个元素:del d[key]

删除整个字典:del d

在删除整个字典后,字典在内存中被销毁,如果再次使用该字典会引发异常NameError

1
2
3
4
5
6
7
8
9
10
11
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
print(cars)

# 删除'BENS'键值对
del cars['BENS']
print(cars)

# 删除整个字典cars
del cars
# 由于cars在内存中被删除,因此打印cars会出错
# print(cars)

任务五:检查字典是否包含指定的key

知识点:类似于列表,使用innot in运算符来检查dict是否包含某个key

1
2
3
4
5
6
7
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
# 判断cars是否包含名为'AUDI'的key
print('AUDI' in cars)
print('PORSCHE' in cars)

# 判断cars是否不包含名为'LAMBORGHINI'的key
print('LAMBORGHINI' not in cars)

8.2.3 字典和列表的比较

任务一:字典的key和列表的索引比较

知识点:

key是字典的精髓,用于元素的索引

key类型可以是整数、浮点数、字符串和元组

字典通过key来实现对元素的访问、添加、删除等操作

知识点:

区别1:列表的索引必须是整数**(0,1,2,…)**,从0开始、连续逐渐增大;但字典的索引即便是整数类型,也不需要从0开始,而且也不需要按顺序

区别2:列表不允许对不存在的索引进行赋值,否则会触发异常IndexError;但字典则允许直接对不存在的key进行赋值,字典自动添加新元素

换句话说,列表和字典都支持用索引来访问任意值,但是字典的key可用的数据类型比列表的索引要多得多

1
2
3
4
5
6
# 列表整数索引
list_age = [20,11,18,30]
print(list_age[0])

#对于不存在的索引赋值会出错
list_age[5] = 1
1
2
3
4
5
6
#字典key索引
dict_age = {'zhang':20, 'li':11, 'wang':18, 'xu':30}
print(dict_age['zhang'])

# 可以对不存在的key赋值,添加为新元素
dict_age['xi'] = 28

任务二:列表和字典的值可以放任意类型对象

知识点(相同):列表和字典的值都可以存放任何类型的对象

1
2
3
4
5
list_age = ['20', 11, [18], {'zhang':20}]
print(list_age)

dict_age = {'zhang':'20', 'li':11, 'wang':[18], 'xu':30}
print(dict_age)

任务三:列表和字典的储存方式

知识点(不同):

列表的元素是有序储存的,Python使用这些连续的整数(位置信息)来访问元素

字典的元素是无序储存的key并不需要与具体元素存储的位置相对应,因此字典key可以是任意的不可变类型

任务四:字典是一种映射方式

知识点:字典提供了一种映射手段,可从一组任意对象映射到有关联的另一组任意对象。类似于现实世界中的字典、辞典和翻译书

下面给出了一段将颜色从英文转换为法文的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
print("---  创建空字典")
english_to_french = {}

print("--- 存入3个单词")
english_to_french['red'] = 'rouge'
english_to_french['blue'] = 'bleu'
english_to_french['green'] = 'vert'

print("--- 获取“red”对应的值")
print("red is", english_to_french['red'])

print('--访问:列表和字典,访问元素时,该元素必须存在,否则会出错--')
print('--赋值:列表赋值元素必须存在,字典赋值元素不一定存在--')
color = input('input color:')
print(color + " is", english_to_french[color])
print('{} is {}'.format(color, english_to_french[color]))

习题:

6-1 人:使用一个字典来存储一个熟人的信息,包括名、姓、年龄和居住的城市。该字典应包含键first_namelast_nameagecity。将存储在该字典中的每项信息都打印出来

1
2
3
4
5
6
7
dic = {'first name':'LeBron',
'last name':'James',
'age':'37',
'city':'Cleveland',
}
for each in dic.items():
print('His ' + each[0] + ' is ' + each[1])
1
2
3
4
His first name is LeBron
His last name is James
His age is 37
His city is Cleveland

6-2 喜欢的数字:使用一个字典来存储一些人喜欢的数字。请想出5个人的名字,并将这些名字用作字典中的键;想出每个人喜欢的一个数字,并将这些数字作为值存储在字典中。打印每个人的名字和喜欢的数字。为让这个程序更有趣,通过询问朋友确保数据是真实的

1
2
3
4
5
6
7
8
favorite_nums = {'James':1,
'Kobe':2,
'Garnett':3,
'Duncan':4,
'Jordan':5,
}
for name,numb in favorite_nums.items():
print(name.title()+"'s favorite number is "+str(numb))
1
2
3
4
5
James's favorite number is 1
Kobe's favorite number is 2
Garnett's favorite number is 3
Duncan's favorite number is 4
Jordan's favorite number is 5

6-3 词汇表:Python字典可用于模拟现实生活中的字典,但为避免混淆,我们将后者称为词汇表。

想出你在前面学过的5个python关键字(转换为字符串),将它们用作词汇表中的键,并将它们的含义作为值存储在词汇表中。

以整洁的方式打印每个词汇及其含义。为此,可以先打印词汇,在它后面加上一个冒号,再打印词汇的含义;也可在一行打印词汇,再使用换行符(\n)插入一个空行,然后在下一行以缩进的方式打印词汇的含义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
programming_vocabulary={
'str()':'将非字符串值表示为字符串',
'del':'彻底删除一个元素',
'sort()':'对列表进行永久性排序',
'sorted()':'对列表进行临时排序',
'range()':'生成一系列数字',
}
print('\nstr()'+':\n\t'+programming_vocabulary['str()'])

print('\ndel'+':\n\t'+programming_vocabulary['del'])

print('\nsort()'+':\n\t'+programming_vocabulary['sort()'])

print('\nsorted()'+':\n\t'+programming_vocabulary['sorted()'])

print('\nrange()'+':\n\t'+programming_vocabulary['range()'])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
str():
将非字符串值表示为字符串

del:
彻底删除一个元素

sort():
对列表进行永久性排序

sorted():
对列表进行临时排序

range():
生成一系列数字

8.3 遍历字典

8.3.1 概述字典的遍历

任务一:初识字典的遍历

知识点:

字典可能只包含几个key-value,也可能包含数百万个key-value。鉴于字典可能包含大量的数据,Python为字典提供了3种遍历方式:

遍历key-value:for key, val in dict.items()

遍历key:for key in dict.keys()

遍历value:for val in dict.value()

字典的遍历就是依次字典中获取所有键值对

1
2
3
4
5
6
7
8
xiaoming = {"name": "小明",
"age": 18,
"gender": True,
"height": 1.75}

# for 循环内部使用的 `key 的变量` in 字典
for k in xiaoming:
print(f"{k}: {xiaoming[k]}")

注意:在实际开发中,由于字典中每一个键值对保存数据的类型是不同的,所以针对字典的循环遍历需求并不是很多

任务二:字典和列表综合遍历

需求分析:

尽管可以使用 for in 遍历 字典

但是在开发中,更多的应用场景是:

使用多个键值对,来存储描述某个 物体 的相关信息 —— 描述更复杂的数据信息

多个物体(字典)放在一个列表中,再进行遍历,在循环体内部针对每一个字典进行相同的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用多个键值对,存储描述一个物体的相关信息
# 来描述更复杂的数据信息。
# 将多个字典放在一个列表中,再进行遍历。
card_list = [
{"name": "张三",
"qq": "12345",
"phone": "110"},
{"name": "李四",
"qq": "54321",
"phone": "10086"}
]

for card_info in card_list:
print(card_info)

8.3.2 items()遍历字典key-value

任务一:items()函数返回key-value数组

知识点:

语法:dict.items()

描述: 为字典dict返回可遍历的(键, 值)元组数组

参数:无

返回:class ‘dict_items’数组类型(可迭代对象),元素为key-value的元组

1
2
3
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
d_items = cars.items()
print(type(d_items), d_items)

任务二:items()函数遍历字典的key-value

知识点:遍历字典所有的key-value

语法:

1
2
for k, v in dict.items():
<缩进语句块>

类似于enumerate()函数,每次迭代items()返回的是一个包含(key, value)的键值对元组

因此,这里需要使用两个临时变量kv对遍历的元组(字典元素)进行解包

k变量:储存键值对的keyv变量:储存键值对的value

1
2
3
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
for k, v in cars.items():
print(f'{k.title()}:{v}', end=' ')

将字典的keyvalue组成一个新的列表

1
2
3
4
5
6
7
8
9
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
result = []
for k, v in cars.items():
result.append((k, v))

print(result)

# 列表推导式
print([(k, v) for k, v in cars.items()])

8.3.3 keys()遍历字典key

任务一:keys()返回字典key数组

知识点:

语法:dict.keys()

描述: 为字典dict返回可遍历的key数组

参数:无

返回:**’class dict_keys’数组类型(可迭代对象),元素为key**

1
2
3
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
d_keys = cars.keys()
print(type(d_keys), d_keys)

任务二:keys()函数遍历字典的key

知识点:遍历字典所有的key

语法:

1
2
for k in dict.keys():
<缩进语句块>

每次迭代keys()返回的是一个元素的key值,存储在临时变量k

1
2
3
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
for k in cars.keys():
print(f'{k.title()}', end=' ')

任务三:查询某个key是否在字典中

知识点:

语法:if k in dict.keys():if k not in dict.keys():

描述:查询变量k是否是字典dictkey

方法keys()并非只能用于遍历;实际上,它返回一个包含字典所有key的数组,然后,使用关键字innot in来查询是否包括某个key

1
2
3
4
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}

if 'Ford' not in cars.keys():
print("Ford not in cars")

任务四:使用sorted()对字典的key进行排序

知识点:

由于字典储存key-value是无序的。因此,使用**keys()**获得元素也是无序的

如果希望对字典的key按升序或降序方式排序,可以使用**sorted(dict.keys())**方式

**sorted(dict.keys())**仅返回排序的拷贝,对字典本身无影响

1
2
3
4
5
6
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}

# 按升序排序
for k in sorted(cars.keys(), reverse=False):
#cars[k]为通过k返回对于的value
print(f'{k}:{cars[k]} ', end=' ')

8.3.4 values()遍历字典value

任务一:values()字典value数组

知识点:

语法:dict.values()

描述: 为字典dict返回可遍历的value数组

参数:无

返回:**’class dict_values’数组类型(可迭代对象),元素为value**

1
2
3
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
d_values = cars.values()
print(type(d_values), d_values)

知识点:遍历字典所有的value

语法:

1
2
for v in dict.value():
<缩进语句块>

每次迭代values()返回的是一个元素的value值,存储在临时变量v

1
2
3
4
5
6
7
8
9
languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}

for v in languages.values():
print(v.title())

程序解析:

这条for语句提取字典中的每个值,并将它们依次存储到变量language

通过打印这些值,就获得了一个列表,其中包含被调查者选择的各种语言

这种做法提取字典中所有的值,而没有考虑是否重复。涉及的值很少时,这也许不是问题,但如果被调查者很多,最终的列表可能包含大量的重复项

任务二:set()剔除重复值

知识点:

为剔除重复项,可使用集合set类型

**class ‘set’**为容器类型(迭代对象)的数据结构

set对象,使用**{}**包含元素,每个元素是唯一的、不重复的

set()函数可以将某个序列转换为set类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}

print("--set数据结构:1.无序 2.不重复 3.{}包含元素--")
set_languages = set(languages.values())
print(type(set_languages), set_languages)

# 遍历set元素
for v in set_languages:
print(v.title())

习题:

6-4 词汇表2:既然你知道了如何遍历字典,现在请整理你为完成练习6-3而编写的代码,将其中的一系列print语句替换为一个遍历字典中的键和值的循环。确定该循环正确无误后,再在词汇表中添加5个Python术语。当你再次运行这个程序时,这些新术语及其含义将自动包含在输出中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
programming_vocabulary={
'str()':'将非字符串值表示为字符串',
'del':'彻底删除一个元素',
'sort()':'对列表进行永久性排序',
'sorted()':'对列表进行临时排序',
'range()':'生成一系列数字',
}

programming_vocabulary['title()']='首字母大写'

programming_vocabulary['lower()']='全部字母小写'

programming_vocabulary['upper()']='全部字母大写'

programming_vocabulary['append()']='在列表末尾添加元素'

programming_vocabulary['insert()']='在列表中插元素'

for key, value in programming_vocabulary.items():
print(key+':\n\t'+value+'.')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
str():
将非字符串值表示为字符串.
del:
彻底删除一个元素.
sort():
对列表进行永久性排序.
sorted():
对列表进行临时排序.
range():
生成一系列数字.
title():
首字母大写.
lower():
全部字母小写.
upper():
全部字母大写.
append():
在列表末尾添加元素.
insert():
在列表中插元素.

6-5 河流:创建一个字典,在其中存储三条大河流及其流经的国家。其中一个键—值对可能是**’nile’: ‘egypt’**

使用循环为每条河流打印一条消息,如“The Nile runs through Egypt.”

使用循环将该字典中每条河流的名字都打印出来

使用循环将该字典包含的每个国家的名字都打印出来

1
2
3
4
5
6
7
8
9
10
dic = {'Euphrates':'Iraq',
'Nile':'Egypt',
'Huanghe':'China',
}
for key, value in dic.items():
print('The ' + key + ' runs through ' + value)
for key in dic.keys():
print(key)
for value in dic.values():
print(value)
1
2
3
4
5
6
7
8
9
The Euphrates runs through Iraq
The Nile runs through Egypt
The Huanghe runs through China
Euphrates
Nile
Huanghe
Iraq
Egypt
China

8.3.5 list()获得key和value列表

任务一:list()获得key和value列表

知识点:

items()keys()values()获得的数据类型不是列表类型,不能对它们实施列表相关操作,比如元素修改、添加或删除、排序等。否则会引起异常TypeError

为此,可以通过**list()**函数将它们转换为列表

1
2
3
4
5
6
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
d_items = cars.items()
print(type(d_items), d_items)

#不能对items()返回结果进行操作,TypeError
d_items[1] = ('BMW', 10.5)
1
2
3
4
5
# 将items()转换为列表
# 或l_items = list(cars.items())
l_items = list(d_items)
print(type(l_items), l_items)
l_items[1] = ('BMW', 10.5)

8.4 字典内置函数和方法

任务一:查看字典常用操作

知识点:

在python中,字典类型是dict

可以通过**dir(dict)**函数查看字典对象里里所包含的属性和方法

暂时忽略**__下划线的属性和方法。dict类为字典操作提供:‘clear()’, ‘copy()’, ‘fromkeys()’, ‘get()’, ‘items()’, ‘keys()’, ‘pop()’, ‘popitem()’, ‘setdefault()’, ‘update()’, ‘values()’**方法

1
print(dir(dict), end=' ')

根据Jupyter智能联想功能,查看字典的函数。步骤如下:

定义一个字典,例如:xiaoming = {}

输入 xiaoming. 再按下TAB键(装有智能联想插件后,不需要按TAB键),Jupyter会提示智能联想字典的所有函数

1
2
3
4
xiaoming.clear       xiaoming.items       xiaoming.setdefault
xiaoming.copy xiaoming.keys xiaoming.update
xiaoming.fromkeys xiaoming.pop xiaoming.values
xiaoming.get xiaoming.popitem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
xiaoming_dict = {"name": "小明",
"age": 18}

# 1. 统计键值对数量
print(len(xiaoming_dict))

# 2. 合并字典
temp_dict = {"height": 1.75,
"age": 20}

# 注意:如果被合并的字典中包含已经存在的键值对,会覆盖原有的键值对
xiaoming_dict.update(temp_dict)

# 3. 清空字典
xiaoming_dict.clear()

print(xiaoming_dict)

任务二:len(dict)函数返回字典元素个数

知识点:**len(dict)**返回字典元素(key-value)的个数

1
2
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
print(len(cars))

任务三:clear()方法清空字典

知识点:

语法:dict.clear()

描述:用于清空字典dict中所有的key-value。对一个字典执行clear()方法之后,该字典就会变成一个空字典

参数和返回:无

del dict区别:del dict将字典从内存中销毁,而dict.clear()只是清空字典,字典dict在内存中依然存在

1
2
3
4
5
6
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
print(cars)

# 清空cars所有key-value
cars.clear()
print(cars)
1
2
3
4
# 在内存中销毁字典cars对象, 之后的语句cars不存在
del cars
# print会出错
print(cars)

任务四:get()方法获取字典元素

知识点:

语法:dict.get(key)

描述:根据key来获取value,它相当于方括号语法**dict[key]**的增强版

dict[key]:访问并不存在的key时,字典会引发KeyError错误

dict.get(key):访问并不存在的key时,会简单地返回None,不会导致错误

参数:要查询的key,不管元素是否存在

1
2
3
4
5
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
# 获取'BMW'对应的value
print(cars.get('BMW')) # 8.5
print(cars.get('PORSCHE')) # None
print(cars['PORSCHE']) # KeyError

任务五:setdefault()方法查询字典元素

知识点:

语法:dict.setdefault(key, default=None)

描述:类似于get()方法, 根据key来获取对应value的值。是增强版的**get()**方法

get()方法的相同:如果key存在,则直接返回key对应的value

get()方法的区别:如果key不存在,先将默认值default作为valuekey一起添加到字典,然后再返回对应的value

参数:要查询的keydefaultkey不存在时的默认值value

返回:key对应的valuedefault

1
2
3
4
5
6
7
8
9
10
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
print(cars)

# 设置默认值,该key在dict中不存在,新增key-value对
print(cars.setdefault('PORSCHE', 9.2)) # 9.2
print(cars)

# 设置默认值,该key在dict中存在,不会修改dict内容
print(cars.setdefault('BMW', 3.4)) # 8.5
print(cars)

任务六:update()方法更新字典元素

知识点:

语法:dict.update(sub_dict)

描述:使用一个字典sub_dict中所包含的key-value来更新字典dict

如果被更新的字典dict中己包含对应的key-value,那么原value会被覆盖

如果被更新的字典dict中不包含对应的key-value,则添加该key-value

参数:字典sub_dict,元素包含需要添加的key-value

返回:无

1
2
3
4
5
6
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
print(cars)

# 'BMW'被更新,'PORSCHE'被添加
cars.update({'BMW':4.5, 'PORSCHE': 9.3})
print(cars)

任务七:pop()方法弹出字典元素

知识点:

语法:dict.pop(key)

描述:获取指定key对应的value,并把这个key-value从字典dict中删除

参数:输入字典dict需要弹出元素的key

返回:key对应的value

1
2
3
4
5
cars = {'BMW': 8.5, 'BENS': 8.3, 'AUDI': 7.9}
print(cars)

print(cars.pop('AUDI')) # 7.9
print(cars) # {'BMW': 8.5, 'BENS': 8.3}

习题:

6-7 人:在为完成练习6-1而编写的程序中,再创建两个表示人的字典,然后将这三个字典都存储在一个名为people的列表中。遍历这个列表,将其中每个人的所有信息都打印出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
dic1 = {'first_name':'jiajia',
'last_name':'amy',
'age':'18',
'city':'shantou',
}
dic2 = {'first_name':'yinyin',
'last_name':'mike',
'age':'28',
'city':'NewYork',
}
dic3 = {'first_name':'bai',
'last_name':'LI',
'age':'38',
'city':'shanghai',
}
dic_ls = [dic1, dic2, dic3]
for index, each in enumerate(dic_ls):
for key, value in each.items():
print(str(index) + '\'s ' + key + ' is ' + value)
1
2
3
4
5
6
7
8
9
10
11
12
0's first_name is jiajia
0's last_name is amy
0's age is 18
0's city is shantou
1's first_name is yinyin
1's last_name is mike
1's age is 28
1's city is NewYork
2's first_name is bai
2's last_name is LI
2's age is 38
2's city is shanghai

6-8 宠物:创建多个字典,对于每个字典,都使用一个宠物的名称来给它命名;在每个字典中,包含宠物的类型及其主人的名字。将这些字典存储在一个名为pets的列表中,再遍历该列表,并将宠物的所有信息都打印出来

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
26
27
28
29
30
31
32
pets = []
pet = {
'animal type': 'python',
'name': 'john',
'owner': 'guido',
'weight': 43,
'eats': 'bugs',
}
pets.append(pet)

pet = {
'animal type': 'chicken',
'name': 'clarence',
'owner': 'tiffany',
'weight': 2,
'eats': 'seeds',
}
pets.append(pet)

pet = {
'animal type': 'dog',
'name': 'peso',
'owner': 'eric',
'weight': 37,
'eats': 'shoes',
}
pets.append(pet)

for pet in pets:
print("\nHere's what I know about " + pet['name'].title() + ":")
for key, value in pet.items():
print("\t" + key + ": " + str(value))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Here's what I know about John:
animal type: python
name: john
owner: guido
weight: 43
eats: bugs

Here's what I know about Clarence:
animal type: chicken
name: clarence
owner: tiffany
weight: 2
eats: seeds

Here's what I know about Peso:
animal type: dog
name: peso
owner: eric
weight: 37
eats: shoes

6-9 喜欢的地方:创建一个名为favorite_places的字典。在这个字典中,将三个人的名字用作键;对于其中的每个人,都存储他喜欢的1~3个地方。为让这个练习更有趣些,可让一些朋友指出他们喜欢的几个地方。遍历这个字典,并将其中每个人的名字及其喜欢的地方打印出来

1
2
3
4
5
6
7
8
9
10
favorite_places={
'James':['hangzhou','wuhan','changsha'],
'Kobe': ['hawaii', 'iceland'],
'Jordan': ['verstovia', 'the playground', 'south carolina']
}

for name,places in favorite_places.items():
print(name.title()+" likes ")
for place in places:
print("- " + place.title())
1
2
3
4
5
6
7
8
9
10
11
James likes 
- Hangzhou
- Wuhan
- Changsha
Kobe likes
- Hawaii
- Iceland
Jordan likes
- Verstovia
- The Playground
- South Carolina

6-10 喜欢的数字:修改为完成练习6-2而编写的程序,让每个人都可以有多个喜欢的数字,然后将每个人的名字及其喜欢的数字打印出来

1
2
3
4
5
6
7
favorite_numbers = {
'James': [23,6],
'Kobe': [24,8],
'Jordan': [45,23,0],
}
for people,number in favorite_numbers.items():
print(people+' like '+str(number))
1
2
3
James like [23, 6]
Kobe like [24, 8]
Jordan like [45, 23, 0]

6-11 城市:创建一个名为cities的字典,其中将三个城市名用作键;对于每座城市,都创建一个字典,并在其中包含该城市所属的国家、人口约数以及一个有关该城市的事实。在表示每座城市的字典中,应包含countrypopulationfact等键。将每座城市的名字以及有关它们的信息都打印出来

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
cities={
'武汉':{
'country':'China',
'population':'1121.20W',
'fact':'Gui',
},
'杭州':{
'country':'China',
'population':'1036W',
'fact':'Tian Mu',
},
'kathmandu': {
'country': 'nepal',
'population': 1003285,
'fact': 'himilaya',
},
}
for city, city_info in cities.items():
country = city_info['country'].title()
population = city_info['population']
mountain = city_info['fact'].title()

print("\n" + city.title() + " is in " + country + ".")
print(" It has a population of about " + str(population) + ".")
print(" The " + mountain + " mountain is nearby.")
1
2
3
4
5
6
7
8
9
10
11
武汉 is in China.
It has a population of about 1121.20W.
The Gui mountain is nearby.

杭州 is in China.
It has a population of about 1036W.
The Tian Mu mountain is nearby.

Kathmandu is in Nepal.
It has a population of about 1003285.
The Himilaya mountain is nearby.

8.5 实例:词频统计

编写一个用于分析文档并计算每个单词在文档中出现的次数的程序。这种文档分析常被用于检测两个文档内容的相似度,也被用于自动索引和归档程序(如互联网搜索引擎)

需求分析:

从程序角度上,只需遍历文档,对每个出现的单词进行累加计数

这里将使用本章学习到的字典,为每个单词建立一个计数器

任务一:构建词频统计字典

建立维护单词计数器的字典counts,其中key是代表文档中的单词的字符串,value是计算单词出现次数的整数。要更新特定单词w的计数,只需要一行代码,当遍历到单词w,那么就将它的计数+1

1
2
# w为单词字符串
counts[w] = counts[w] + 1

任务二:更新词频统计

对词频字典counts更新词频的统计。在这里使用字典会遇到一个Bug。第一次遇到一个单词时,由于字典counts中还没有该单词,如果对它进行访问counts[w]会引起KeyError异常。为了防范这种情况,需要在算法中做出判断:

如果字典counts中已经存在单词w那么就对它进行+1

如果单词w不存在,那么就向字典添加新元素

方法一:为检测某个key是否在字典中存在,可以使用in运算符:

1
2
3
4
if w in counts:
counts[w] = counts[w] + 1
else:
counts[w] = 1

方法二:更优雅的方法是使用setdefault()方法,如果w不在字典中,将返回0,结果是w的条目设置为1:

1
2
# 如果不存在,则添加新元素,初始值为0
counts[w] = counts.setdefault(w,0) + 1

任务三:文件输入和预处理

在分析文件词频前,需要对文本文档拆分成一系列的单词。但在拆分之前,需要做如下两个操作:

将所有文本单词统一转换为小写(这样出现“Foo”将匹配“foo”)

消除标点符号(这样“foo,”匹配“foo”)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 输入文件名比如 'hello.txt'
fname = input("File to analyze: ")

# 将整个文件读取为一个长字符串
# open(fname,"r")为'r'只读模式打开文件,然后再调用read()读文件
# encoding = 'UTF-8'指定文件编码类型'UTF-8'
text = open(fname,'r', encoding = 'UTF-8').read()

# 所有字符转换为小写
text = text.lower()
# 删除标点,将文本的标点符号统一替换为空格' '
for ch in '!"#$%&()*+,-./:;<=>?@[\\]^_‘{|}~':
  text = text.replace(ch, " ")

# 字符串的split()方法将字符串按空格拆分为words列表
words = text.split()

任务四:更新字典词频

遍历单词列表words,构建字典counts

1
2
3
counts = {}
for w in words:
counts[w] = counts.get(w, 0) + 1

任务五:对词频进行排序

按词频的降序排序,总结counts的内容

方法一:打印所有单词。按字母顺序打印出单词列表及其关联的计数

1
2
3
4
5
6
7
8
9
# 获得所有单词,即字典的key
uniqueWords = list(counts.keys())

# 对单词列表进行排序
uniqueWords.sort()

# 再打印排序结果
for w in uniqueWords:
print(w, counts[w])

方法二:打印前n个单词。然而,对于一个大文件,很多单词仅出现少数几次。更好的方式是打印文档中前n个最常见单词的计数。为此,需要创建一个按计数排序的列表c_words,然后从列表中选择前n

首先用字典的items()方法,获取键值对的列表,这里的c_words是一个字典的key-value元组列表

1
2
# 将items()返回结果转换为list类型
c_words = list(counts.items())

然后,对列表c_words进行排序

如果直接使用列表排序**c_words.sort()**,Python会按默认的排序方法

然而,当Python比较元组时,它会按部分从左到右排序。由于key-value元组的第一个部分是单词,所以c_words.sort()将会按照字母顺序排列此列表

为了能让列表排序按词频(key-value元组的第二个部分),可以自定义**sort()的排序规则。注意,元组像列表一样从0开始索引,所以pair[1]**将元组的词频部分返回

1
2
3
#自定义排序规则,pair为列表元素(元组),按词频pair[1]排序
def byFreq(pair):
return pair[1]

将排序规则通过key参数传给**c_words.sort()**函数:

1
2
# 设定排序规则函数
c_words.sort(key=byFreq)

双重排序:希望对的列表主要按词频排序,但在词频相同时按字母顺序排列。如何处理这种双重排序呢?

解决方法:如果在按词频排序之前,所有单词按照字母顺序排列,那么具有相同词频的单词仍将按照字母顺序排列。为此,只需要对列表进行两次排序,先按单词排序,再按频率排序:

1
2
c_words.sort() #先按单词字母升序排序
c_words.sort(key=byFreq, reverse=True) #后按词频降序排序

任务六:输出结果

按照从最频繁到最不频繁的顺序排列,打印前 n 个最常见的单词的报告。通过格式化字符串形式遍历列表c_wordsn个元素:

1
2
3
4
for i in range(n):
#列表元素是元组,解包元组
word, count = c_words[i]
print("{0:<15}{1:>5}".format(word, count))

索引i用于从列表c_words中获取c_words[i]元素(元组),并将该元组解包到wordcount中。

然后通过**.format()**函数格式化输出字符串,单词格式15个空格左对齐,词频5个空格右对齐

任务七:最终程序

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
26
27
28
29
30
def byFreq(pair):
  return pair[1]


print("此程序对文件单词(英语)进行词频分析")
print("并输出前n个词频最高的单词.\n")

# 输入文件:Python_Data.txt
fname = input("File to analyze: ")
text = open(fname,'r', encoding = 'UTF-8').read()
text = text.lower()
for ch in ’!"#$%&()*+,-./:;<=>?@[\\]^_‘{|}~’:
text = text.replace(ch, ’ ’)
words = text.split()

# 构建词频统计字典
counts = {}
for w in words:
counts[w] = counts.setdefault(w,0) + 1

# 排序前n项词频统计
n = eval(input("Output analysis of how many words? "))
c_words = list(counts.items())
c_words.sort()
c_words.sort(key=byFreq, reverse=True)

# 格式化输出结果
for i in range(n):
word, count = c_words[i]
print("{0:<15}{1:>5}".format(word, count))

8.6 (总结) 四大容器类型公共方法

8.6.1 内置函数

对于容器类型,Python包含了以下内置函数:

函数 描述 备注
len(item) 计算容器中元素个数
del(item) 删除变量 del有两种方式
max(item) 返回容器中元素最大值 如果是字典,只针对 key比较
min(item) 返回容器中元素最小值 如果是字典,只针对 key比较

知识点:比较运算符

直接使用比较运算符来对有序类型数据作比较

**cmp(item1, item2)**函数在Python3中已被淘汰

知识点:

字符串的比较规则按Unicode码顺序

数字字符**<大写字母<**小写字母。即 “0” < “A” < “a”

知识点:Unicode码扩展自ASCII

ASCII使用8位宽(1字节)来对字符进行编码

Unicode使用16位宽(2字节)

这使得Unicode能够表示世界上所有的书写语言中可能用於电脑通讯的字元、象形文字和其他符号

前127个的Unicode码与ASCII码一样

8.6.2 切片

知识点:

切片适合字符串、列表、元组数据类型

切片使用索引值来限定范围,提取子序列

字符串的切片操作:从一个大的字符串切出小的字符串。例如:**”0123456789”[::-2]**,切片结果为 “97531”

列表元组的切片操作:它们都是有序的集合,都能够通过索引值获取到对应的数据。因此,也支持切片操作

字典 是一个无序的集合,是使用键值对保存数据。不能使用切片操作

8.6.3 运算符

运算符 表达式 结果 描述 支持的数据类
+ [1, 2] + [3, 4] [1, 2, 3, 4] 合并 字符串、列表、元组
* [“Hi!”] * 4 [‘Hi!’, ‘Hi!’, ‘Hi!’, ‘Hi!’] 重复 字符串、列表、元组
in 3 in (1, 2, 3) True 元素是否存在 字符串、列表、元组、字典
not in 4 not in (1, 2, 3) True 元素是否不存在 字符串、列表、元组、字典
> >= == < <= (1, 2, 3) < (2, 2, 3) True 元素比较 字符串、列表、元组

知识点:innot in 被称为成员运算符

成员运算符用于测试序列中是否包含指定的成员

in运算符:

如果在指定的序列中找到值返回 True,否则返回 False

3 in (1, 2, 3) 返回 True

not in运算符:

如果在指定的序列中找不到值返回 True,否则返回 False

3 not in (1, 2, 3) 返回 False

注意:在对字典操作时,判断的是字典的key

8.6.4 完整的for-else循环语法

Python 中完整 for 循环 的语法是带有else语句块的

1
2
3
4
for 变量 in 集合:    
循环体代码
else:
没有通过 break 退出循环,循环结束后,会执行的代码

需求:当迭代遍历嵌套的数据类型时,要判断某个字典中是否存在指定的值

如果存在,提示并且退出循环

如果不存在,在循环整体结束后,希望得到一个统一的提示

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
26
27
28
29
30
students = [
{"name": "阿土",
"age": 20,
"gender": True,
"height": 1.7,
"weight": 75.0},
{"name": "小美",
"age": 19,
"gender": False,
"height": 1.6,
"weight": 45.0},
]

find_name = "阿土"

for stu_dict in students:

print(stu_dict)

# 判断当前遍历的字典中姓名是否为find_name
if stu_dict["name"] == find_name:
print("找到了")

# 如果已经找到,直接退出循环,就不需要再对后续的数据进行比较
break

else:
print("没有找到")

print("循环结束")

评论