本章学习目标 .理解序列、映射、数据可变与不可变的概念 .熟练掌握元组数据类型的使用方法 .熟练掌握列表数据类型的使用方法 .熟练掌握字典数据类型的使用方法 .掌握集合数据类型的使用方法 前4章讨论的都是一些相对简单的问题,程序中存储和处理的数据比较少,而且数据与 数据之间都相对独立。对于复杂的问题来说,需要处理的数据量一般都比较大,而且数据之 间往往存在关联。举个例子来说,如果要处理一个学校开设的课程情况,就要把表示课程信 息的数据,包括课程编号、课程名称、学分等相互关联的数据项组织到一起处理,类似这样的 问题就要借助组合数据类型来实现。本章研究组合数据类型及应用。主要介绍元组、列表、 字典、集合4种组合数据类型及应用。 5.1 元组及其应 用 扫一扫 5.1.1 元组概述 1. 元组的含义 元组是使用一对圆括号括起来的0个或多个数据元素的序列。如()、(1,2,3)、("a", "b,(") (") c(") )都是元组。 对元组有以下4点说明。 (1)元组中的数据元素可以是包括元组在内的任意数据类型。 128 (2)元组中元素的个数叫作元组的长度。 (3)含有0个元素的元组(一对空的圆括号)叫作空元组。 (4)若元组中只有一个元素,书写时元素的后面必须跟一个逗号。 2 . 定义元组 定义元组的一般格式如下。 变量名= 元组 在IDLE命令交互方式下定义元组的程序示例如图5-1所示。在该程序中,第1个变量定义 了空元组t1。第2个变量定义了只有一个整数元素1的元组t2。该条语句里1后面的逗号是必 须要有的,否则系统会把1当作为普通的整数处理。第3个变量定义了含三个整数元素的元组 t3,存了某个人的三科考试成绩。第4个变量定义了含三个浮点数元素的元组t4,存了三个季度 的GDP增长率。最后一个变量定义了元组t5,存了一个学生的姓名、年龄和三科考试成绩。它 含有三个不同数据类型的元素,自左向右依次是字符串类型、整数类型、元组类型。 图5-1 定义元组的程序示例 3 . 一维和多维元组 可以通过圆括号的层数来确定元组的维数。只含一层圆括号的元组叫作一维元组。含 有两层圆括号的元组叫作二维元组。同样的道理,含有三层圆括号的元组叫作三维元组,含 有四层圆括号的元组叫作四维元组……依此类推。 如: (1,2,3)是一维元组。 (1,2,(3))是二维元组。 (1,2,(3,(4)))是三维元组。 二维及二维以上的元组叫作多维元组。 5.1.2 元组处理 1 . 访问元素 和字符串一样,元组中的元素也是使用序号来表示其在序列中的位置,且同样拥有非负 129 序号和负序号两种格式。 一维元组t1=(1,2,3)中元素的序号如图5-2所示。其中,非负序号自左向右是0~2, 负序号自左向右是-3~-1。 对于多维元组来说,每一层圆括号中的元素都采用相同的方法确定序号。二维元组 t2=(1,(2,3))中元素的序号如图5-3所示。其中,第一层圆括号中的元素1和(2,3),其非 负序号自左向右是0~1,负序号自左向右是-2~-1。第二层圆括号中的元素2和3,非负 序号自左向右也是0~1,负序号自左向右也是-2~-1。 图5-2 一维元组中元素的序号 图5-3 二维元组中元素的序号 和检索字符串中字符的方法一样,可以通过序号来访问元组中的元素。 访问元组中元素的一般格式如下。 元组变量名[序号] 对于一维元组t1=(1,2,3)来说,t1[1]和t1[-2]访问的都是左边第2个元素2。对于 二维元组t2=(1,(2,3))来说,t2[1]和t2[-1]访问的都是左边第2个元素(2,3),它是一 个一维元组。 访问多维元组里元素的格式如下。 元组变量名[序号1][序号2]…[序号n ] 其中,序号1、序号2、……、序号n 分别用来表示该元素所处的第1层、第2层、……、第 n 层圆括号里的序号。很显然,访问的元素处于第几层圆括号里,就要带几个序号。 对于二维元组t2=(1,(2,3))来说,如果要访问元素2,就要带2个序号,可以使用 t2[1][0]、t2[1][-2]、t2[-1][0]、t2[-1][-2]表示。 2 . 元组切片 和字符串一样,元组也可以进行切片。元组切片的方法及注意事项与2.4.2节中介绍 的字符串切片完全一样,这里不再赘述。 字符串切片与元组切片的不同如下。 (1)字符串切片的结果是字符串类型。 (2)元组切片的结果是元组类型。 在IDLE命令交互方式下对元组进行切片的程序示例如图5-4所示。可以对照图5-4(b) 所示的存储情况加以理解。 3 . 元组运算 和字符串类似,Python中用于元组的运算符如表5-1所示。 130 图5-4 元组切片程序示例 表5-1 元组的运算符和表达式 运 算 符实施运算表 达 式 + 合并运算t1+t2 * 复制运算t*n in 包含运算t1int 其中,合并运算(+)用来将运算符右边元组中的元素按原有顺序合并到左边元组最后 一个元素后面,生成一个新的元组。复制运算(*)用来生成原元组的若干副本,并将其合并 为一个新的元组。包含运算(in)用来判断一个对象是否是元组的元素。 在IDLE命令交互方式下使用元组运算的程序示例如图5-5所示。 图5-5 元组运算程序示例 在这个程序中,先定义了含3个整数1、2、3的元组t1和含3个字符串"a""b""c"的元 组t2,之后进行t1+t2运算,结果是生成了一个含6个元素的元组(1,2,3,a' ',b' ',c' ')。之后 进行t1*3运算,结果是将t1复制了3次,并合并成了一个含9个元素的元组(1,2,3,1,2, 3,1,2,3)。之后判断(1,2)是否为t1的元素,结果是False。最后判断(1,2)是否为元组 ((1,2),(2,3))的元素,结果为True。 4 . 常用函数与方法 Python提供了4个用于元组处理的内置函数,如表5-2所示。 131 表5-2 内置元组处理函数 函 数功 能 len(t) 求元组t 的长度,即元素个数 max(t) 求元组t 中元素的最大值 min(t) 求元组t 中元素的最小值 tuple(seq) 将seq转换为元组类型 在IDLE命令交互方式中使用几个函数的程序示例如图5-6所示。 图5-6 使用元组处理函数的程序示例 在这个程序中,先定义了一个字符串变量s 和3个元组变量t、t1、t2。t、t1、t2分别存 了含4个数值型元素、3个字符串元素、4个复数元素。之后执行len(t),求t 的元素个数, 结果是4。执行max(t),求t 中元素的最大值,结果是5.2。执行min(t1),求t1中元素的 最小值,结果是字符串"ab"。执行max(t2),求t2中元素的最大值,程序运行出错,因为在 3.1.1节中介绍过复数类型的数据无法比较大小。最后执行tuple(s),结果是把字符串 "abc"转换成了含三个元素的元组(a' '、b' '、c' ')。 除了内置函数,还有2个重要的元组处理方法,如表5-3所示。 表5-3 2个元组处理方法 方 法功 能 t.count(value) 返回元组t 中值为value的元素个数 t.index(value) 返回元组t 中值为value的元素首次出现的序号 图5-7 使用元组处理方法的程序示例 在IDLE命令交互方式下使用两个方法的程序 示例如图5-7所示。 在上面的程序中,首先定义了含8个元素的元 组t,之后使用count函数统计值为1的元素个数, 结果是3。使用index函数求值为3的元素首次出 现的序号,结果是2。 5. 元组的特性 元组是一种不可变的数据类型。这种不可变性体现在元组一旦被定义,就只能作为一 个整体进行赋值,不可以对单个元素进行赋值。 有关元组不可变的程序示例如图5-8所示。 图5- 8 元组不可变的程序示例 在该程序中,元组t1开始存储了某旅游公司开出的3个旅游项目("滑雪","游泳","狩 猎"),后来公司发展,把项目扩展到了4个("滑雪","游泳","狩猎","购物"),所以对元组 t1作为一个整体重新进行了赋值,这样做是可以的。后面试图把第2个元素t1[1]修改为" 冲浪",结果引发了错误。系统提示,元组类型不支持对元素赋值操作。 元组的这种不可变特性可以保护其内部的数据,确保数据的安全。 5.1.3 2 个程序设计实例 1. 输出星期信息 扫一扫【实例5-1】编程实现,输入一个1到7之间的整数,输出与输入数字对应的“星期一” 至“星期日”的信息。 经过分析,“星期一”至“星期日”是7个固定不变的字符串,符合元组不可变的特点,可 以使用一维元组weks来存储。为了操作方便,可以令它含8个元素,第1个元素存空串 (""),这样,只要令输入的数字 n 作元组weks的序号,取到的恰好就是与该数字相对应的 星期几的信息。 一维元组weks的存储结构简图如图5-9所示。 图5- 9 一维元组weks的存储结构简图 根据上面的分析,确定了程序的数据结构,需要一个一维元组weks和一个整型变量 n,分别用来存星期几的信息和输入的数据。 程序的算法流程图如图5-10所示。 程序的完整代码和运行效果如图5-11所示。第4~5行是定义元组weks的代码, 实质上是一条语句,可以直接写成多行,不需要使用反斜杠(\)续行。weks里含8个元素,(它) 132 图5-10 【实例5-1】的算法流程图 序号为0的是空串,尽管它在编程时没有用,但是加入了它,使得后面其他7个元素的序号 是几,对应的元素就是字符串“星期几”,这就给问题处理带来了很大的方便。第10~14 行 是一个双路分支结构,用来控制输入1~7的数时就输出“今天是星期几”的信息,否则就输 出“输入的不是1至7之间的数字!” 的信息。图5-11(b)是单独运行程序两次的运行效果 截图。 图5-11 【实例5-1】的程序代码和运行效果 2. 求已过去的天数 【实例5-2】编程实现,输入1980 年1月1日之后的年、月、日,输出该年度经过了的 天数。 经过分析,12 个月的天数是固定不变的整数,符合元组不可变的特点,可以使用一个含 两个一维元组的二维元组month_days来存储。 二维元组month_days的存储结构简图如图5-12 所示。 在图5-12 中,第1行的序号为0,存了不是闰年时各月份的天数;第2行的序号为1,存 133 图5-12 二维元组month_days存储结构简图 了闰年时各月份的天数。为了处理方便,可以令每行含13 个元素,序号为0的元素存0,其 他序号的元素存储该序号对应月份的天数。 程序运行时,根据输入的年是否为闰年决定从哪一行中取值———闰年从第2行取值,不 是闰年从第1行取值。然后遍历1至输入的月份减1,累计每个月的天数之和。遍历结束 时加上最后一个月的天数(也就是输入的天数), 即可求得结果。 这里可以定义一个变量leap,用它存是否是闰年的结果。它的值是逻辑值True或 Fas2.3节介绍过, Fle对应的是0,Tu如果让 le,2.逻辑值是整数的子集,asre对应的是1, leap做month_days的序号,就可以解决根据是否是闰年从二维元组中准确取值的问题。 基于上述分析确定了程序的数据结构,如表5-4所示。 表5- 4 【实例5-2】数据结构信息 变量名数据类型作用 month_days tuple 存储不是闰年和闰年每个月的天数 year int 存输入的年 month int 存输入的月 day int 存输入的日 leap bool 存是否是闰年的信息 i int 控制遍历月份 days int 累计经历的天数 程序的算法流程图如图5-13 所示。 程序的完整代码及运行效果如图5-14 所示。 在该程序中,第5~8行是二维元组的定义部分。第15 行把输入的非整月的天数存到了 day1.~22 s中。第18 行是判断闰年的语句,用到了3.2节中介绍过的判断闰年表达式。第21 行是一个遍历循环结构,用于累计整月的天数。请注意,第5~8行二维元组month_days的定 义写成了多行,且进行了对齐处理;第11~13 行输入语句里也进行了对齐处理,这都是好的编 程习惯,因为这样的代码结构更清晰,更容易阅读。第22 行用到了5.2节介绍的使用双序号 1. 访问二维元组元素的方法。 图5-14(b)给出了两次运行程序,分别输入1980 年5月1日和2021 年5月1日的运行 效果,因为前者是闰年,后者不是闰年,所以结果差了一天。 134 图5-13 【实例5-2】的算法流程图 图5-14 【实例5-2】的程序代码及运行效果 135 136 5.2 列表及其应用 5.2.1 列表概述 1 . 列表的含义 列表是使用一对方括号括起来的0个或多个数据元素的序列。如[]、[1,2,3]、["a", "b","c"]都是列表。 对列表有以下3点说明。 (1)列表中的数据元素可以是包括列表在内的任意数据类型。 (2)列表中元素的个数叫作列表的长度。 (3)含有0个元素的列表(一对空的方括号)叫作空列表。 2 . 定义列表 定义列表的一般格式如下。 变量名= 列表 在IDLE命令交互方式下定义列表的程序示例如图5-15所示。 图5-15 定义列表程序示例 在该程序中,第1个变量定义了空列表l1。第2个变量定义了只有一个整数元素的列 表l2。请注意,和元组不同,当列表只有一个元素时,元素后面不需要写逗号。第3个变量 定义了含3个整数元素的列表l3,存了3科考试成绩。第4个变量定义了含3个浮点数元 素的列表l4,存了3个季度的GDP增长率。最后一个变量定义了列表l5,存了某学生选修 的一门课程信息,包括课程名称、学分和3次考试成绩,3个元素自左向右分别是字符串类 型、浮点类型和列表类型。 3 . 一维和多维列表 可以通过方括号的层数来确定列表的维数。只含一层方括号的列表叫作一维列表。含 扫一扫