4.5 元组(Tuple)
元组是Python内置的不可变序列,与列表一样由若干元素有序组合,但元组中的元素不能添加、修改、删除和排序。
元组是用圆括号括起来的若干个元素,其间使用逗号分隔。
tup = (1, 3.5, '字符串:', [5, 7.8])
其中的值可以是任何类型,并且按照整数下标索引,与列表类似。
因为元组不可变,所以代码更安全。
元组与列表功能大部相同,只有()和元组不可变不同。所以说元组是不可改变的列表。
除了会违反不变性的列表运算符,其他序列的操作都可用于元组。
元组的应用场景是当存放在列表中的数据只供查询,不再允许修改时,如学校中的学生毕业后,这些学生的数据已是过去的确定数据,就不能修改和删除了,此时这些数据就应存放在元组中。因此,在Python中就需要进行元组与列表的相互转换。
list()可以将元组转换成列表,tuple()可以将列表转换成元组。
list_x = [3,2.5,[8,'c'],'apple','b'] # 列表print(f'data: {list_x}, type:{type(list_x)}') # 输出列表数据及类型tup_x = tuple(list_x) # 将列表转换成元组print(f'data: {tup_x}, type:{type(tup_x)}') # 输出元组数据及类型for x in tup_x: # 元组的遍历 print(x, end=',')tup_x[1] = tup_x[1]*2 # 修改元组数据将触发异常list_y = list(tup_x) # 将元组转换成列表list_y[-1] = 88.8 # 修改数据print(f'\ndata: {list_y}, type:{type(list_y)}') # 输出列表数据及类型
代码执行情况如下:
data: [3, 2.5, [8, 'c'], 'apple', 'b'], type:<class 'list'>
data: (3, 2.5, [8, 'c'], 'apple', 'b'), type:<class 'tuple'>
3,2.5,[8, 'c'],apple,b,Traceback (most recent call last):
File "C:\Python310\10.py", line 7, in <module>
tup_x[1] = tup_x[1]*2 # 修改元组数据将触发异常
TypeError: 'tuple' object does not support item assignment
可以发现代码运行到第7行时,因元组不可变的性质,修改元组数据时触发了异常。将第7行注释或删除,再运行代码就可正常执行了。
4.5 字典(dictionary)
通过前面2节的介绍,读者可以看到使用列表存储数据很方便,且还可以根据需要按指定的数据进行排序,所以列表在Python中的使用很多。虽然列表有很多优点,但有一个很大的缺点:当列表中数据很多时,要查询到指定的数据很多(数据的定位)时就很困难了,这时字典就可以弥补这方面的缺点,数据最多也可以很方便地查询到指定数据。
字典是一种集合,它不是序列(是无序的)。字典由若干个元素组成,每个元素由键(key):值(value)对构成,中间用冒号“:”分隔,其中“:”前的是键(key),后的是值(value);键值对之间用逗号“, ”分隔。字典相当于书的目录,键是目录名,值是该目录的对应内容。
整个字典包括在花括号 {} 中,字典中的键不能重复(即键是唯一的),格式如下:
dict = {键1 : 值1 , 键2 : 值2, ……}
值可以是任何数据类型,但键必须是不可变的,如字符串,数字或元组。
字典元素(键key:值value对)举例:
'语文': 90 '姓名': '李明'
'单词': '频率' 'Monday': '星期一'
字典是以 {} 定义的,字典中每个元素包含两个部分,键和值。
d ={} #或 d = dict() # 创建一个空的字典print(f'{d},\ttype:{type(d)}')# 输出字典数据及类型d1={"id":19,"name":"Marry","city":"chongqing"} # 创建一个字典print(f'{d1}')
也可通过dict()来创建字典。即:使用其它映射或包含(键、值)两个值的序列对建立。
# 由(键、值)两个值的序列对建立创建字典d2 = dict(id=19,name="Marry",city="chongqing")print(f'{d2}')# 输出字典数据# 由(键、值)两个值的序列对建立创建字典scores =[("高数",89),("Python",92),("大学英语",93)] # 外是列表,内是元组(2个元素:键,值)#scores =(("高数",89),("Python",92),("大学英语",93))#scores =[["高数",89],["Python",92],["大学英语",93]]dictscores = dict(scores)print(f'{dictscores}')# 输出字典数据
2、添加和修改字典 ★★
字典的大小是动态的。添加和修改的方法:
字典名[键名] = 键值
如字典中已存在该键,则为修改,否则为添加。
d1 = {"高数": 89, "大学英语": 85, "体育":'良好'}print(f'{d1}') # 输出字典数据d1["高数"] = 78 #"高数"键存在,则修改print(f'{d1}') # 输出修改后的字典数据{'高数': 78, '大学英语': 85, '体育': '良好'}d1["Python"] = 90 #"Python"键不存在,则添加print(f'{d1}') # 输出修改后的字典数据
代码执行情况如下:
{'高数': 89, '大学英语': 85, '体育': '良好'}
{'高数': 78, '大学英语': 85, '体育': '良好'}
{'高数': 78, '大学英语': 85, '体育': '良好', 'Python': 90}
3、查询 ★★
因字典是无序的,因此不能像列表一样通过索引来访问元素,必须通过键(即:字典名[键])来查询值,这个操作称为“查询”。
方法是: 字典名['键名']
d1 = {"高数": 89, "大学英语": 85, "体育":'良好'}print(f'{d1}') # 输出字典数据# 输出高数的成绩,注意:因输出时使用了f-string格式,因此键名高数要用"高数"括起来print(f'高数的成绩={d1["高数"]}') print(f'体育的成绩={d1["体育"]}') # 输出体育的成绩#if'良好'in d1: #可以先判断,有再取值print(f'{d1["良好"]}') # 输出良好的成绩。因d1没有名为“良好”的键,故会触发异常
代码执行情况如下:
{'高数': 89, '大学英语': 85, '体育': '良好'}
高数的成绩=89
体育的成绩=良好
Traceback (most recent call last):
File "C:\Python310\10.py", line 7, in <module>
print(f'{d1["良好"]}') # 输出良好的成绩。因d1没有名为“良好”的键,故会触发异常
KeyError: '良好'
可以看到,当键存在时,使用字典名['键名']取值非常方便。但当键不存在时,则将触发异常。因此使用这种单独指定键名取值方式时,应在取值前增加一个条件判断,当键存在时再取值,如上面代码中的第6行。
用for循环语句可以方便地遍历字典中每个元素的键和值。但字典不是序列,而for语句中in后要求是一个序列,因此一般不直接放字典名,而是使用字典的方法keys()。
dic.keys():返回一个视图对象。使用list()返回字典的键列表。在Python的for语句中可以直接使用dic.keys(),不必一定要写list(dic.keys())。
d1 = {"高数": 89, "大学英语": 85, "体育":'良好'} # 创建字典for key in d1.keys(): # 遍历字典。 print(key, d1[key]) # 输出字典的值(键与值)#为方便使用,也可以写成: for key in d1:for key in d1: # 遍历字典。与上个for语句相同 print(key, d1[key]) # 输出字典的值(键与值)
5、字典长度、检索
len(dic)函数 返回字典中键的数量
a In dic 测试某个特定的键a是否在字典dic中
6、字典的常用方法
① dic.get(key[,value]) :如果字典中存在关键字key,则返回关键字key对应的值,若key不在字典中,则返回value的值,value默认为None,该方法不会改变原对象的值。
从3、查询介绍中可以知道:直接使用字典名['键名']取值时可能会出现因键名不存在而触发异常,因此为避免这种情况,python提供了一个get()方法用于安全的取值。
d2={"高数": 89, "大学英语": 85, "体育":'良好'} # 创建字典s1 = d2.get("大学英语") # 取'大学英语'课程的成绩print(f'大学英语:{s1}') # 输出大学英语课程的成绩s2 = d2.get("Python") # 取'Python'课程的成绩。注意:Python中的P是大写,但实际上字典中是小写print(f'Python:{s2}') # 输出Python课程的成绩,为None(空值)值s3 = d2.get("Python","Python不存在") # 调用ger方法时,添加value项print(f'Python:{s3}') # 输出Python课程的成绩,为'Python不存在'
代码执行情况如下:
大学英语:85
Python:None
Python:Python不存在
此时,虽然'Python'在字典中不存在,但因使用get()方法取值,就不会触发异常了,保存了代码的正常运行。
例4-11:输入两个数字,并输入“+”“-”“*”“/”运算符号,输出运算结果。若输入其他符号,程序则退出
编程分析:
定义一个以四个运算符为键的字典,用于计算对应的计算
使用input()函数输入2个数字
再使用input()函数输入1 个运算符
调用字典的get()方法根据运算符计算结果
输出计算结果
据此,相关代码设计如下:
whileTrue: try: x = int(input("请输入x=")) y = int(input("请输入y=")) except ValueError: print("输入数据错误") continue op = input("请输入运算符:") if op not in ['+','-','*','/']: break # 定义一个以四个运算符为键的字典,用于计算对应的计算 di = {'+':x+y, '-':x-y, '*':x*y, '/':x/y} s = di.get(op) # 用运算符调用get()方法获得计算结果 print(f"{x}{op}{y}={s}") # 输出运算表达式和结果
代码执行情况如下:
请输入x=5
请输入y=6
请输入运算符:*
5*6=30
请输入x=16
请输入y=5
请输入运算符:/
16/5=3.2
请输入x=5
请输入y=5
请输入运算符:5
② dic.pop(key[,value]) :删除某一项。如果字典中存在关键字key, 删除并返回关键字key对应的值。若key不在字典中,如没有设置[,value]参数,则出错;否则返回value的值。
d2 = {"高数": 89, "大学英语": 85, "体育":'良好'} # 创建字典print(f'创建的字典:{d2}') # 输出字典s5 = d2.pop("大学英语") # 删除'大学英语'键对应的元素print(f'大学英语:{s5}') # 输出删除的'大学英语'课程成绩print(f'删除大学英语后的字典:{s5}') # 输出删除的'大学英语'课程成绩s6 = d2.pop("Python") # "Python"键不存在,因没有设置value而触发异常s7 = d2.pop("Python","Python不存在") # "Python"键不存在,但因设置value就不触发异常print(f'{s7}') # 输出Python不存在信息
代码执行情况如下:
创建的字典:{'高数': 89, '大学英语': 85, '体育': '良好'}
大学英语:85
删除大学英语后的字典:85
Traceback (most recent call last):
File "C:\Python310\10.py", line 6, in <module>
s6 = d2.pop("Python") # "Python"键不存在,因没有设置value而触发异常
KeyError: 'Python'
可以看到,程序运行时执行到第6行就触发异常而停止运行。因此,调用pop()方法时,应使用value参数,避免程序出错。用第7行代码代替第6行代码,程序运行正常。
③ dic.keys(): ★★
返回一个视图对象。使用list()将字典中的键以列表形式返回
d2 = {"高数": 89, "大学英语": 85, "体育":'良好'} # 创建字典print(f'字典的键:{d2.keys()}') # 输出字典键的视图对象li = list(d2.keys()) # 转换成列表print(f'字典的键:{li}') # 输出字典键的列表
代码执行结果:
字典的键:dict_keys(['高数', '大学英语', '体育'])
字典的键:['高数', '大学英语', '体育']
④ dic.values() :返回视图对象。以列表形式返回字典中的所有值
⑤ dic.items(): 返回视图对象。将字典中的所有项以列表形式返回可遍历的(键, 值) 元组数组
d2 = {"高数": 89, "大学英语": 85, "体育":'良好'} # 创建字典print(f'创建的字典:{d2}') # 输出字典v = d2.values() # 字典中所有值的视图对象print(f'字典中所有值的视图对象:{v}') # 输出字典所有值的视图对象v = list(d2.values()) # 将字典中所有值的视图对象转换成列表print(f'字典中所有值的列表:{v}') # 输出字典中所有值的列表liit = list(d2.items()) # 将字典中所有键值对的视图对象转换成列表print(f'字典中所有键值对的列表:{liit}') # 输出字典中所有键值对的列表
代码执行结果:
创建的字典:{'高数': 89, '大学英语': 85, '体育': '良好'}
字典中所有值的视图对象:dict_values([89, 85, '良好'])
字典中所有值的列表:[89, 85, '良好']
字典中所有键值对的列表:[('高数', 89), ('大学英语', 85), ('体育', '良好')]
例4-12:某公司销售部分A、B两组,对销售部员工的销售额按组进行统计。
【输入描述]第一行输入一个整数N,然后再输入N行数据,每行两个字符串和一个整数,分别对应员工姓名、组别、销售额。
【输出描述]生成一个关于A、B两组销售额的字典,分行输出A、B两组的销售总额,组别和销售额之间用空格分隔,并在最后一行输出所有员工的平均销售额,保留2位小数。
【输入样例】
4
张三 A 1500
李四 B 2000
赵六 A 2500
王七 B 1200
【运行结果】
编程分析:
第一个整数n,通过input()函数调用得到,并转换成整数;
定义一个空字典dic,用于存放后面输入的各组数据,组名为键;
使用一个循环次数为n的for循环:
使用input()函数输入一个员工的数据(1行)。因1行中含有3个数据,数据间使用空格分隔,因此需输入的数据进行split()分解成3个数据;
使用if语句,判断该员工的所在组是否存在于字典dic中,若不存在,说明dic中还没有该组的数据,因此将该员工的销售额转换成整数后赋值给该健;否则说明存在该组的数据,则将该员工的销售额转换成整数后与原有该健的值累加;
循环结束后,n个员工的数据已按组累加到字典中,输出字典;
dic.values()中存放了每组的销售额,对此执行sum()操作,求出销售总额,再除于n就是平均销售额。
至此,相关设计代码如下:
n = eval(input()) # 输入人数dic ={} # 定义一个空字典,用于存放每组的销售额for i inrange(n): # 循环n次 name,group,num = input().split() # 每次循环输入1行数据,并分解 if group not in dic: # 输入的组是否存在字典中 dic[group] = int(num) # 不存在,直接存放 else: # 存在,累加存放 dic[group] +=int(num)print('生成的字典为:', dic)print('A、B两组的销售总额分别如下:')forgroupin dic: print(group, dic[group])print(f"所有员工的平均销售额为:{sum(dic.values())/n:.2f}")
⑥ dic.fromkeys(iterable [,value]): ★★★
以给定的序列(iterable)各元素值为键(key),依次添加到字典dic中,添加的每个键(key)默认的值为None。如有相同键,则按字典规则:键不能重复,合并处理保留一个。
t = ('IBM', 'Python', 'Taobao', 'IBM')d1 = dict.fromkeys(t) # 不带value参数的fromkeys()方法# 输出经fromkeys()方法创建的字典,因没有使用value参数,故每个键的值均为Noneprint(f'创建的字典:{d1}')d2= {}.fromkeys(t, 0) # 带value参数的fromkeys()方法# 输出经fromkeys()方法创建的字典,因使用了value参数,故每个键的值均为value指定的值print(f'创建的字典:{d2}')
上述代码执行结果如下:
创建的字典:{'IBM': None, 'Python': None, 'Taobao': None}
创建的字典:{'IBM': 0, 'Python': 0, 'Taobao': 0}
例4-13:从键盘上输入一行英文句子,句子中可能含有英文的逗号和句号。英文句子中的英文单词前后可能含有逗号、句号和(或),然后按照英文句子中单词的出现次序,统计每个单词出现的次数。单词不区分大小写,"To" 和"to"看作一个单词。要求以单词(小写形式)作为"键",以出现的次数作为"值",按照字典的形式输出。
【输入描述】从键盘上输入一行英文句子。
【输出描述】按照英文句子中单词(小写形式)出现次序,以单词作为"键",以出现的次数作为"值",按照字典的形式输出。
【输入样例】To be, or (not to) be, is a question, question.
编程分析:
英文文章中,单词与单词之间使用空格分隔,因此先使用input()输入一行英文,然后将输入的一行英文使用split()方法进行分解;
因分解后的英文单词前后含有标点字符,因此用一个列表推导式将英文单词前后含有标点字符删除:li_words = [x.strip(',.()') for x in line.split()];
然后使用dic_word = {}.fromkeys(li_words ,0) 以英文句子中单词的出现次序分解的单词为键添加到字典中,键的值为0。即每个单词的数量初始化为0;
使用for语句遍历li_words,对每次出现的单词的数量加1:dic_word[word] += 1。循环结束,dic_word字典中就是每个单词出现的次数;
最后输出dic_word字典
据此,实现上述功能的代码如下:
text = input("请输入一个句子:").lower()li_words = [x.strip(',?.;!:') for x in text.split()] #将句子解析成单词并去除标点# 将列表转化为字典dic_word = {}.fromkeys(li_words, 0) # 创建单词字典,每个单词的数量初始化为0forwordin li_words: dic_word[word] += 1 # 相同的单词word,数量加1print(f"{dic_word}")
代码执行情况如下:
请输入一个句子:To be, or (not to) be, is a question, question.
{'to': 1, 'be': 2, 'or': 1, '(not': 1, 'to)': 1, 'is': 1, 'a': 1, 'question': 2}
⑦ dic.clear() :
删除字典dic中的所有“键-值”对,变成一个空字典。
⑧ d2.update(d1):用字典d1中的“键:值”对更新或添加到字典d2中,即将字典d1合并到字典d2 ,对于字典d1中有但字典d2没有的添加到字典d2中,而字典d1中有但字典d2也有的以字典d1中的健值更新到字典d2中。
d2 = {"高数": 89, "大学英语": 85, "体育":'良好'}print(f'原始字典d2:{d2}')d1 = {'物理':90, '体育':88}# 用字典d1更新字典d2。字典d2中添加了键为'物理'的键值对,更新了'体育'键的值d2.update(d1) # 用字典d1更新字典d2print(f'字典d2:{d2}')print(f'字典d1:{d1}') # 字典d1没有变化
代码执行结果如下:
原始字典d2:{'高数': 89, '大学英语': 85, '体育': '良好'}
字典d2:{'高数': 89, '大学英语': 85, '体育': 88, '物理': 90}
字典d1:{'物理': 90, '体育': 88}
⑨ 字典的排序
因字典是无序的,因此字典本身不能直接进行排序,可以先将字典转化为列表,使用列表的排序功能进行排序后,再转化为字典的方法解决。
如要在例4-13中添加一个功能,在统计单词出现的次数后,再按单词出现次数的高低进行降序排序,输出降序排序后的单词字典。
编程分析:
dic_word字典中是原始的单词次数字典,它不能直接排序,先将它转化成列表: li_word = list(dic_word.items());
列表li_word中的每个元素是以键值对的元组,每个元素有2个值:单词和单词出现的次数。现题意要求按单词出现次数的高低进行降序排序,因此直接使用列表的sort()方法或sorted()函数都无法解决,所以就需要使用sort()方法或sorded()函数的key参数,按指定的函数来确定排序的规则。这个函数可以使用Python的匿名函数lambda完成,lambda语法格式如下:
lambda [形式参数列表] : <表达式>
排序时,排序的元素是一个元组t,但题目的要求排序是按单词的次数进行降序排序,因此是该元组的第2个元素,即t[1],因此,这里传入的形式参数就是t,出来的表达式就是t[1]。lambda t : t[1]
所以列表的排序就是: list_word.sort(key=lambda t : t[1], reverse=True)
将排序完成后列表转化为字典;
最后输出字典。
据此,实现代码如下:
text = input("请输入一个句子:").lower()li_words = [x.strip(',?.;!:') for x in text.split()] #将句子解析成单词并去除标点# 将列表转化为字典dic_word = {}.fromkeys(li_words, 0) # 创建单词字典,每个单词的数量初始化为0forwordin li_words: dic_word[word] += 1 # 相同的单词word,数量加1print(f"{dic_word}")#按单词出现次数降序排序list_word = list(dic_word.items()) #字典没有专用的排序,因此需按项目转化为列表list_word.sort(key=lambda t : t[1], reverse=True)dic_worded = dict(list_word) # 将排序后的列表转化为字典print(f"排序后的字典:{dic_worded}")