前言
在实际开发过程中,我们会遇到需要将相关数据关联起来的情况,例如,处理学生的学号、姓名、年龄、成绩等信息。另外,还会遇到需要将一些能够确定的不同对象看成一个整体的情况。Python提供了字典和集合这两种数据结构来解决上述问题。
本文首先介绍字典的创建和基本操作方法,然后介绍字典的遍历和嵌套,接着介绍集合的概念以及常用操作方法,最后通过两个典型案例的分析和实现,让读者进一步掌握在程序中使用字典和集合的方法。
一、字典的创建和访问
1.1 字典的创建
字典是Python中常用的一种数据存储结构,它是由**"键-值"对** 组成,每个"键-值"对称为一个元素,每个元素表示一种映射或对应关系。
- **"键"**可以是Python中任意不可变数据,如整数、实数、复数、字符串、元组等类型,但不能使用列表、集合、字典或其他可变类型作为字典的"键"。
- "值" 可以取任意数据类型。
**(1)**直接赋值创建字典
直接赋值创建字典的一般格式如下:
python
变量名 = {键1:值1, 键2:值2, 键3:值3,...}
例如:创建一个学生信息字典,包括学生学号、姓名和性别三个元素。
python
>>>stu_info = {'num':'20180101', 'name':'Liming', 'sex':'male'} #创建字典
>>>stu_info #查看字典
{'name':'Liming', 'num':'20180101', 'sex':'male'}
**Tips:**字典中元素打印出来的顺序与创建时的顺序不一定相同,这是因为字典中各个元素并没有前后顺序。
**(2)使用内置函数dict()**创建字典
还可以用内置函数dict()通过其他"字典"、"(键,值)"对的序列或关键字参数来创建。
python
stu_info1 = {'num':'20180101', 'name':'Liming', 'sex':'male'} #直接赋值创建字典
stu_info2 = dict(stu_info1) #通过其他字典创建
stu_info3 = dict([('num', '20180101'), ('name', 'Liming'), ('sex', 'male')]) #通过"(键,值)"对的序列创建
stu_info4 = dict(num = '20180101', name = 'Liming', sex = 'male') #通过关键字参数创建
stu_info5 = dict(zip(['num', 'name', 'sex'], ['20180101', 'Liming', 'male'])) #通过dict和zip结合创建
if stu_info1 == stu_info2 == stu_info3 == stu_info4 == stu_info5: #判断五个变量是否相等
print("创建字典的5种方式相同") #如果相同输出提示符
else: #如果不相同
print("创建字典的5种方式不相同") #输出提示符

**Tips:**zip()函数将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的zip对象。
**(3)使用fromkeys()**方法创建字典
在Python中,当所有键对应同一个值时,可使用fromkeys()方法创建字典。
python
dict.fromkeys(seq[,value])
- seq为字典"键"值列表
- value为设置键序列(seq)的值,省略时默认为None
python
>>>stu_age1=dict.fromkeys(['Wangwu','Zhangsan']) #创建字典,"键"的值默认为None
>>>stu_age1 #输出stu_age1
{'Wangwu':None, 'Zhangsan':None}
>>>stu_age2=dict.fromkeys(['Wangwu','Zhangsan'],'18') #创建字典,"键"的值默认为18
>>>stu_age2 #输出stu_age2
{'Wangwu':'18', 'Zhangsan':'18'}
**Tips:**字典中的"键"是唯一的,创建字典时若出现"键"相同的情况,则后定义的"键-值"对将覆盖先定义的"键-值"对。
python
>>>x = {'a':1, 'b':2, 'b':'3'} #直接赋值创建字典x
>>>x #输出字典x
{'a':1,'b':'3'}
1.2 字典的访问
(1)根据键访问值
字典中的每个元素表示一种映射关系,将提供的"键"作为下标可以访问对应的"值",如果字典中不存在这个"键"则会抛出异常。其语法格式如下:
python
字典变量名[键]
python
>>>stu_info = {'num':'20180105', 'name':'Yinbing', 'sex':'male'} #创建字典
>>>stu_info['num'] #根据num访问学号
'20180105'
>>>stu_info['age'] #指定的键不存在抛出异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'age'
**(2)使用****get()**方法访问值
在访问字典时,若不确定字典中是否有某个键,可通过get()方法进行获取,若该键存在,则返回其对应的值,若不存在,则返回默认值。其语法格式如下:
python
dict.get(key[,default=None])
- dict为被访问字典名
- key是要查找的键
- default定义默认值,如果指定键的值不存在,返回该默认值,当default为空时,返回None
python
>>>stu_info.get('name') #get()获取学生姓名
'Yinbing'
>>>stu_info.get('age') #get()获取学生年龄,返回值为None
>>>print(stu_info.get('age')) #输出返回值None
None
>>>stu_info.get('age',18) #设置返回默认值为18
18
二、字典的基本操作
2.1 修改和添加元素
当以指定"键"为下标为字典元素赋值时,有两种含义:
(1)若该"键"在字典中存在,则表示修改该"键"对应的值;
(2)若该"键"不存在,则表示添加一个新的"键-值"对,也就是添加一个新元素到字典中。
python
>>>stu_info={'num':'20180105','name':'Yinbing','age':'17'} #创建字典
>>>stu_info['age']='18' #修改age的值
>>>stu_info['age'] #输出修改后的age值
'18'
>>>stu_info['sex']='male' #添加学生性别
>>>stu_info #输出添加后的字典
{'num': '20180105', 'name': 'Yinbing', 'age': '18', 'sex': 'male'}
2.2 删除元素
要删除字典中的元素或整个字典,可以使用del命令、clear()、pop()和popitem()方法。
del命令:可根据"键"删除字典中的元素。
python
>>>stu_info={'num':'20180105','name':'Yinbing','age':'17'} #创建字典
>>>del stu_info['age'] #删除age及其值
>>>stu_info #输出删除后的字典
{'num': '20180105', 'name': 'Yinbing'}
clear()方法:用于清除字典中的所有元素:dict.clear()
- dict为要被清空的字典名
- 该方法不包含任何参数,也没有返回值
python
>>>stu_info={'num':'20180105','name':'Yinbing','age':'17'} #创建字典
>>>stu_info.clear() #清空字典
>>>stu_info #输出清空后的字典
{}
pop()方法:用于获取指定"键"的值,并将这个"键-值"对从字典中移除:dict.pop(key[,default])
- dict为要被删除元素的字典名
- key是要被删除的键
- default是默认值,当字典中没有要被删除的key时,该方法返回指定的默认值
python
>>>stu_info={'num':'20180105','name':'Yinbing','age':'17'}#创建字典
>>>stu_info.pop('age') #返回并删除age"键-值"对
'17'
>>>stu_info.pop('age',18) #无指定键,返回默认值18
18
popitem()方法:用于随机获取一个"键-值"对,并将其删除:dict.popitem()
- dict为要被删除元素的字典名
- 该方法无参数,返回值为一个随机的"键-值"对
python
>>>stu_info={'num':'20180105','name':'Yinbing','age':'17'} #创建字典
>>>stu_info.popitem() #随机返回某"键-值"对并删除
('age', '17')
>>>stu_info #输出字典
{'num': '20180105', 'name': 'Yinbing'}
2.3 更新****字典
update()方法:可以将新字典的"键-值"对一次性全部添加到当前字典中,如果两个字典中存在相同的"键",则以新字典中的"值"为准更新当前字典:dict.update(dict2)
- dict为当前字典
- dict2为新字典
python
>>>stu_info = {'num':'20180105', 'name':'Yinbing', 'age':'17'} #创建字典
>>>stu_info.update({'age':'18', 'sex':'male'}) #修改age的值,同时添加新元素
>>>stu_info #输出字典
{'num':'20180105', 'name':'Yinbing', 'age':'18', 'sex':'male'}
2.4 复制字典
复制字典可调用copy()方法,copy()方法返回字典的浅复制:dict.copy()
- dict为需要复制的字典
- 该方法无参数,返回值为一个新字典
python
>>>stu_info={'num':'20180105','name':'Yinbing','age':'17'}
>>>stu_info.copy()
{'num': '20180105', 'name': 'Yinbing', 'age': '17'}
**Tips:**在Python3中,可以用三种方法复制字典:直接赋值、浅复制和深复制。
(1)直接赋值:对象的引用。
(2)浅复制(copy()方法):拷贝父对象,引用对象内部的子对象。
(3)深复制(deepcopy()方法):copy模块的deepcopy()方法,完全复制父对象及其子对象。
例:直接赋值、浅复制和深复制的区别:
python
dict1 = {'user':'runoob','num':[1,2,3]}
dict2 = dict1 #引用对象
dict3 = dict1.copy() #浅复制,深复制父对象,子对象不复制,还是引用
import copy
dict4 = copy.deepcopy(dict1) #深复制,完全复制父对象及其子对象
dict1['user'] = 'root' #将dict1中键为'user'的值改为'root'
dict1['num'].remove(1) #移除dict1中键为'num'的列表值中的1
#输出结果
print('dict1=',dict1)
print('dict2=',dict2)
print('dict3=',dict3)
print('dict4=',dict4)

三、字典的遍历
3.1 **遍历字典中所有的"键-**值"对
遍历字典中所有的"键-值"对需要用到items()方法,该方法以列表形式返回可遍历的"(键,值)"元组。
dict.items()
python
stu_class = {
'Mary':'C',
'Jone':'Java',
'Lily':'Python',
'Tony':'Python'
} #定义字典并赋值
for name, cla in stu_class.items(): #遍历"键-值"对
print(name,'选修的是',cla) #输出每个值

3.2 遍历****字典中所有的键
当不需要使用字典中的值时,可使用keys()方法只遍历字典中的键,该方法以列表返回一个字典中所有的键:dict.keys()
python
stu_class = {
'Mary':'C',
'Jone':'Java',
'Lily':'Python',
'Tony':'Python'
} #定义字典并赋值
for name in stu_class.keys(): #遍历字典所有的键
print(name) #输出每个键

3.3 遍历字典中所有的值
当只关心字典所包含的值时,可使用values()方法,该方法以列表形式返回字典中所有的值:
dict.values()
python
stu_class = {
'Mary':'C',
'Jone':'Java',
'Lily':'Python',
'Tony':'Python'
} #定义字典并赋值
print('以下课程已被选择:')
for cla in stu_class.values(): #遍历字典所有的值
print(cla) #输出每个值

四、嵌套
4.1 在****列表中嵌套字典
例:在列表中嵌套字典:
python
student_info1 = {'name':'Wangmi', 'sex':'F', 'age':'15'} #定义字典student_info1并赋值
student_info2 = {'name':'Linmei', 'sex':'M', 'age':'14'} #定义字典student_info2并赋值
student_info3 = {'name':'Chenhui', 'sex':'F', 'age':'14'} #定义字典student_info3并赋值
student = [student_info1, student_info2, student_info3] #创建包含三个学生的列表
for s in student: #遍历列表
print(s)

4.3 在****字典中嵌套字典
例:在字典中嵌套字典:
python
stu_info = {
'WangMi':{'sex':'F','age':'15'},
'LinMei':{'sex':'M','age':'14'},
'ChenHui':{'sex':'F','age':'14'}
} #定义字典并赋值
for name, stu in stu_info.items(): #遍历字典所有元素
print(name,'性别',stu['sex'],'年龄',stu['age']) #输出键和值

4.2 在字典中嵌套列表
例:在字典中存储列表:
python
stu_class = {
'Mary':['C','Math'],
'Jone':['Java','Art'],
'Lily':['Python'],
'Tony':['Python','Mysql','Math']
} #定义字典并赋值,字典中的值为列表
for name,cla in stu_class.items(): #遍历字典所有的元素
print(name,'选的课程是:',) #输出键
for c in cla: #遍历列表
print(c)

五、集合
5.1 集合的创建
集合(set)与数学中集合的概念一致,即包含0个或多个数据项的无序组合。
- 集合中的元素不可重复
- 元素类型只能是固定数据类型,如整数、浮点数、字符串、元组等
- 不能是列表、字典和集合等可变数据类型
**Tips:**Python提供了一个内置函数hash()来计算对象的哈希值,凡是无法计算哈希值(调用内置函数hash()时抛出异常)的对象都不能作为集合的元素,也不能作为字典对象的"键"。
python
>>>hash('Python') #计算字符串的哈希值
-5336376190899570360
>>>hash(1) #计算整型数据的哈希值
1
>>>hash([1,2,3]) #计算列表的哈希值,抛出异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
(1)直接创建
创建集合的方式很简单,只需将逗号分隔的不同元素使用大括号括起来即可:
python
>>>a_set = {1, 2, 3, 4} #创建集合并赋值
>>>a_set #输出集合a_set
{1, 2, 3, 4}
>>>b_set = {2, 1, 3, 4, 1, 2} #创建集合并赋值
>>>b_set #输出集合b_set
{1, 2, 3, 4}
由于集合元素是无序的,集合的打印效果与定义顺序可以不一致,且由于集合元素独一无二,使用集合类型能够过滤掉重复元素。
**(2)使用****set()**函数
set()函数:将列表、元组等其他类型的数据转换为集合,如果原来的数据中存在重复元素,则在转换为集合时会将其删除。
python
>>>x = set('runoob') #将字符串转换为集合
>>>x #输出集合x
{'o', 'u', 'n', 'b', 'r'}
>>>y = set(['g', 'o', 'o', 'g', 'l', 'e']) #将列表转换为集合
>>>y #输出集合y
{'g', 'o', 'e', 'l'}
>>>z = set() #空集合
>>>z #输出集合z
set()
**Tips:**集合类型与其他类型最大的不同在于它不包含重复元素,因此,当需要对一维数据进行去重处理时,一般可通过集合来完成。
例:将输出数据去除重复项后输出:
python
stu_class = {
'Mary':'C',
'Jone':'Java',
'Lily':'Python',
'Tony':'Python'
} #定义字典并赋值
print('以下课程已被选择:')
for cla in set(stu_class.values()): #遍历字典所有的值,调用set()将列表转换为集合从而去除重复项
print(cla) #输出每个值

5.2 集合的基本操作
(1)添加与删除集合元素
|---------------------|-----------------------------|
| 操作函数或方法 | 描 述 |
| S.add**(x)** | 如果数据项x不在集合S中,将x添加到S中 |
| S.update**(T)** | 合并集合T中的元素到当前集合S中,并自动去除重复元素 |
| S.pop() | 随机删除并返回集合中的一个元素,如果集合为空则抛出异常 |
| S.remove(x) | 如果x在集合S中,移除该元素;如果x不存在则抛出异常 |
| S.discard(x) | 如果x在集合S中,移除该元素;如果x不存在不报错 |
| S.clear() | 清空集合 |
python
>>>s = {1, 2, 3} #创建集合并赋值
>>>s.add(4) #添加元素
>>>s.update({4, 5, 6}) #更新当前集合,自动忽略重复元素
>>>s #输出集合
{1, 2, 3, 4, 5, 6}
>>>s.discard(5) #删除元素,不存在则忽略该操作
>>>s #输出集合
{1, 2, 3, 4, 6}
>>>s.remove(5) #删除元素,不存在则抛出异常
KeyError:5
>>>s.pop() #删除并返回一个元素
1
(2)集合****运算
内置函数len()、max()、min()、sorted()等也适用于集合,另外,Python集合还支持数学意义上的交集、并集、差集、补集等运算:
|-----------|-----------------------------------------------------|
| 操 作 符 | 描 述 |
| S&T | 交集,返回一个新集合,包括同时在集合S和T中的元素 |
| S|T | 并集,返回一个新集合,包括集合S和T中的所有元素 |
| S-T | 差集,返回一个新集合,包括在集合S中但不在集合T中的元素 |
| S^T | 补集,返回一个新集合,包括集合S和T中的元素,但不包括同时在集合S和T中的元素 |
| S<=T | 如果S与T相同或S是T的子集,返回True,否则返回False,可以用S<T判断S是否是T的真子集 |
| S>=T | 如果S与T相同或S是T的超集,,返回True,否则返回False,可以用S>T判断S是否是T的真超集 |
python
>>>a_set = {1, 2, 3, 4, 5} #创建集合并赋值
>>>b_set = {1, 2, 6, 7, 8} #创建集合并赋值
>>>a_set & b_set #交集
{1, 2}
>>>a_set | b_set #并集
{1, 2, 3, 4, 5, 6, 7, 8}
>>>a_set - b_set #差集
{3, 4, 5}
>>>a_set ^ b_set #补集
{3, 4, 5, 6, 7, 8}
>>>x = {1, 2, 3} #创建集合并赋值
>>>y = {2, 3} #创建集合并赋值
>>>z = {1, 2, 4} #创建集合并赋值
>>>x >= y #y是否为x的子集
True
>>>x <= z #x是否为z的子集
False
六、案例实战
python
count =0 #定义count变量并赋初值为0
passwd=123 #定义passwd变量并赋初值为123
dict1={'alex':[passwd,count],'Tom':[passwd,count]} #定义字典用于存储用户信息
while True: #开始循环
name = input("please input your name:") #输入用户名
password = int(input("please input your password:")) #输入密码
if name not in dict1.keys(): #如果输入的用户名不在字典中
print("name %s is not in dict"%name) #输出提示语
break #跳出循环
if dict1[name][1] > 2: #如果次数大于2
print("the name %s locked"%name) #输出被锁定提示信息
break #跳出循环
if password == dict1[name][0]: #如果输入的密码正确
print("login ok") #输出登录成功提示语
break #跳出循环
else: #密码输入错误
print("name or passwd error") #输出提示语
dict1[name][1] +=1 #次数加1



python
data = {
'北京': {
'昌平':
{
'沙河': ['沙河机场', '链家'],
'天通苑': ['北方明珠', '天通尾货']
},
'朝阳':
{
'花家地': ['朝阳公园', '望京soho'],
'北小河': ['北小河公园', '北京中学']
}
},
'上海': {
'虹桥':
{
'虹桥机场': ['超市', '特产店', '水吧'],
'东方明珠': ['电影院', '游泳馆', '餐馆']
},
'浦东':
{
'景秀路': ['世纪公园', '立交桥'],
'中环路': ['鲁迅公园', '同济大学']
}
},
'河北': {
'石家庄':
{
'行唐': ['东正', '阳关'],
'赵县': ['赵州桥', '高村乡']
},
'唐山':
{
'滦南县': ['司各庄镇', '安各庄镇'],
'玉田县': ['玉田镇', '亮甲店镇']
}
}
}
while True:
for i in data: #打印第一级列表
print(i)
choice = input("请选择省或直辖市(退出请按q):")
if choice in data: #如果在第一级列表里则进入下一级列表
while True:
for i2 in data[choice]: #打印第二级列表
print(i2)
choice2 = input("请选择(退出请按q返回省或直辖市列表请按b):")
if choice2 in data[choice]: #如果在第二级列表里则进入下一级
while True:
for i3 in data[choice][choice2]: #打印第三级列表
print(i3)
choice3=input("请选择(退出请按q返回上一级列表请按b):")
if choice3 in data[choice][choice2]:
for i4 in data[choice][choice2][choice3]:
print(i4)
choice4 = input("已经到达最后一级(退出请按q返回上一级列表请按b):")
if choice4 == 'b':
continue
elif choice4 == 'q':
exit()
elif choice3 == 'b': #从第三级返回第二级
break
elif choice3 == 'q':
exit()
elif choice2 == 'b': #从第二级返回第一级
break
elif choice2 == 'q':
exit()
elif choice == 'q':
exit()
