第3章 Python程序控制结构          程 序控制结构是编程中的基本构建块,它们使程序能够根据输入、数据和逻辑条件做出决策,实现不同的任务和功能。 3.1 程序结构 3.1.1 程序流程图   程序流程图是一种用统一规定的图形化符号表示计算机程序执行流程的工具。它通常用于可视化程序的结构和逻辑,以便开发人员更容易理解和分析程序的运行方式。它是程序分析和过程描述的最基本也是最常用的方式。   程序流程图包括各种符号和线条,用于表示不同的程序元素和它们之间的关系。以下是程序流程图中常见的一些元素,对应的图形符号如图3-1所示。 图3-1?流程图示例   1. 开始或结束符号   通常用一个椭圆形表示程序逻辑的开始或结束。   2. 流程步骤   流程步骤用矩形框表示,包含具体的操作或计算步骤。这些步骤通常按顺序排列,表示程序的主要逻辑。   3. 连接线   用箭头线条表示不同元素之间的流程方向,表示程序执行的顺序或分支条件。   4. 条件语句   条件语句用菱形表示,表示根据条件表达式的不同结果,程序会选择不同的分支路径。通常在菱形内部写明条件,例如,x > 0。   5. 输入或输出   输入或输出用平行四边形表示,表示程序与外部世界的数据输入和输出。   6. 连接点   连接点用于多个流程图的连接,用圆圈表示,圈内标注要连接子流程图的标号,常用于将多个较小流程图组织成较大流程图。 3.1.2 程序流程结构   程序的执行顺序由程序结构决定,Python中的程序有三种结构:顺序结构、分支结构和循环结构。   顺序结构按顺序依次执行程序语句。顺序结构是最简单的一种程序结构,它是按照先后顺序依次执行程序中的每一条语句。如第2章的例2-2~例2-6。   但是在实际应用中,只有顺序结构远不能完成复杂问题,常常会用到分支结构和循环结构。分支结构是根据条件判断来选择相应的程序运行,循环结构可以实现多次运行一条或多条语句。 3.2 分支结构   分支结构是根据条件表达式的值来选择程序运行的语句,分为单分支结构、双分支结构和多分支结构。   此外,在一个分支结构内部可以包含另一个或多个分支结构,即条件语句嵌套。这样就可以完成更为复杂的功能。 3.2.1 单分支结构:if语句   1. 语法格式   if语句的语法格式如下:      if <条件表达式> :    <语句块>      2. 说明   (1)<条件表达式>:一个条件用>(大于)、<(小于)、==(等于)、>=(大于或等于)、<=(小于或等于)等来表示数据关系,条件表达式可以是一个或多个条件组合(and , or , not)。   条件表达式的值为布尔型(bool),真为True,假为False。   此外,Python程序语言指定任何非0和非空(Null)值为真(True),0 或者Null为假(False)。   当条件表达式的值为“真”时,则执行其后的语句块。   当条件表达式的值为“假”时,跳过if结构,继续执行if结构体后面的语句。单分支结构的流程图如图3-2所示。   (2)<语句块>:当<条件表达式>的值为“真”时,所执行的程序语句。程序内容可以多行,以采用缩进方式来区分同一范围。   【例3-1】 在例2-4的基础上,添加性别条件判断。只计算男生的基础代谢率。   【任务实现】   任务分析:由于只计算男生的基础代谢率,所以可以使用单分支程序结构。由于存在两种性别情况,所以程序测试两次,分别测试男或女。具体程序代码及运行结果如图?3-3所示。 图3-3 单分支示例 3.2.2 双分支结构:if-else语句   1. 语法格式   if-else语句的语法格式如下:      if <条件表达式> :    <语句块1>   else:    <语句块2>   endif      2. 功能   根据条件表达式的真假情况执行不同的代码块,当条件表达式的值为真(True)时,则执行语句块1;否则执行语句块2,从而实现两种情况的分类处理。双分支结构流程图如图3-4所示。 图3-4?双分支结构流程图   【例3-2】 在例3-1的基础上,完善性别条件判断。根据不同的性别,计算对应的基础代谢率。   【任务实现】   任务分析:由于性别存在两种情况,所以可以使用双分支程序结构。   具体程序代码及运行结果如图3-5所示。 图3-5?双分支示例   【例3-3】 简化例3-2。   【任务实现】   任务分析:基础代谢率的计算公式如下: 男性:10 × 体重(kg)+ 6.25 ×身高(cm)? 5 ×年龄 +5 女性:10 × 体重(kg)+ 6.25 ×身高(cm)? 5 ×年龄 ?161   分析基础代谢率的计算公式可以发现,不同性别的公式就是最后一项不同,所以可以先用男性公式计算,如果是男性则可以直接输出结果,如果是女性则在这个数据的基础上减166即可。   简化后的程序就变成了单分支结构,具体程序代码及运行结果如图3-6所示。 图3-6?例3-2程序的简化 3.2.3 多分支结构:if-elif-else语句   1. 语法格式   if-elif-else语句的语法格式如下:      if <条件表达式1> :    <语句序列1>   elif <条件表达式2>:    <语句块2>    ……   elif <条件n-1> :    <语句块n-1>   else :    <语句块n>   endif      2. 功能   多分支结构允许根据不同条件的多个可能性来分别执行不同的语句块,以实现多种情况的分类处理。该结构流程图如图3-7所示。 图3-7?多分支if-elif-else结构流程图   【例3-4】 在例3-3的基础上,继续完善性别条件判断。   【任务实现】   任务分析:用户可能输入的性别数据不只是0(女)或1(男),还有其他可能,那么可以使用多分支程序结构。具体程序代码及运行结果如图3-8所示。 图3-8?多分支示例   【例3-5】 完善例3-4,当性别输入数据不对时不再进行其他数据的输入。   【任务实现】   任务分析:用户可能输入的性别数据不是0(女)或1(男)时,就不需要输入体重等数据。这时可以使用条件语句的嵌套来实现。   第一层分支语句先进行性别数据判断,符合输入要求的情况下,再进行第二层计算男女不同的基础代谢率。   具体程序代码及运行结果如图3-9所示。 图3-9?多分支示例 3.2.4 多分支结构:match-case 语句   Python 3.10引入了match-case语句,也称为“模式匹配”或“结构化匹配”。match-case语句允许用户根据不同的模式匹配执行不同的代码块,使得多情况处理更为强大和灵活,且代码简洁,提高了可读性。   1. 语法格式   match-case 语句的语法格式如下:      match <表达式> :    case <模式1>:    <语句块1>    case <模式2>:    <语句块2>    ……    case <模式n-1>:    <语句块n-1>    case _ :    <语句块n>      2. 功能   match-case可以用于各种不同的模式匹配情况,包括常量、范围、类型、条件等。它的程序流程图如图3-10所示。 图3-10?多分支match-case结构流程图   match后面跟要匹配的变量,case后面跟不同的条件,之后是符合条件需要执行的语句。最后一个“case_”表示默认匹配,即如果前面的case条件都没有匹配上就执行这项,类似之前的else。   3. 说明   case常用的模式匹配:   ① 单一值:直接写具体数据。   ② 多个值:用竖线“|”隔开;或者用“in [值1,值2,…, 值n]”列表方式。例如,case x if x in [95,96,97],其中x是临时变量。   ③ 范围:用“if”条件模式判断,例如,case x if x >= 90。   【例3-6】 根据所输入的成绩,按五分制给出不同的评价。对于个别特别优秀的同学,给予特别的评价。   【任务实现】   任务分析:五分制的评价标准为不及格(0~59)、及格(60~69)、中(70~79)、良(80~89)和优(90~100)。对于95之上的特别优秀的同学给予特别的评价。这里涉及多种情况分类处理,所以可以考虑用match-case语句实现。   具体程序代码如图3-11所示。 图3-11?成绩转换   【例?3-7】 根据所输入的基础代谢率数据,计算不同活动状态下的每日能量消耗 (TDEE,Total Daily Energy Expenditure)。   每日能量消耗估算方法: 每日能量消耗=基础代谢率?活动强度系数   其中,活动强度系数如下: * 久坐或基本不运动:1.2。 * 轻度活动:1.375,例如,每周运动1~3次。 * 中度活动:1.55,例如,每天运动或每周剧烈运动3~5次。 * 积极活动:1.725,例如,每周剧烈运动6~7次。 * 高强度活动:1.9,例如,每天高强度运动或重体力劳动者。   【任务实现】   这里涉及多种活动状态下的系数处理,所以可以考虑用match-case语句实现。具体程序代码如图3-12所示。 图3-12?计算每日能量消耗   【思考题】   参考例3-5和例3-7的程序实现过程,根据用户所输入的性别、体重、身高、年龄和平时活动状态,计算该用户的每日能量消耗。 3.3 循环结构   循环结构是指在程序中需要反复执行某个功能而设置的一种程序结构。它由循环体中的条件,判断继续执行某个功能还是退出循环。   根据判断条件,循环结构又分为两种形式:遍历循环(for循环)和条件循环(while循环)。此外,Python还提供了控制循环的关键字和语句,如break(用于提前结束当前循环)、continue(用于结束当此循环)、以及else(用于在循环正常结束时执行一段代码块)。 3.3.1 遍历循环:for循环   遍历循环又称为for循环,用于遍历可迭代对象(如列表、元组、字符串等)中的元素,并执行代码块。它通常在已知迭代次数且有规律变化时的情况下使用。for循环是一种先判断后执行的循环结构。   1. 语法格式   for循环的语法格式如下:      for <循环变量> in <遍历对象>:    <循环体>      2. 说明   <遍历对象>:可迭代对象,如列表、元组、字符串等。   <循环体>:当有可遍历的对象元素时所执行的程序语句。循环执行持续到所有元素遍历完全后或遇到break语句时才结束循环。循环体中的一部分语句也可以是一个循环结构,即循环嵌套:循环体内又有循环体,这样可以构成双重循环、三重循环……   for循环结构的流程图如图3-13所示。 图3-13?for循环结构的流程图   3. range()函数   在for循环中,通常会用到range()函数来控制循环的迭代次数。range()函数可以创建一个表示一系列整数的不可变序列。   range()函数的语法格式如下。      range(, [stop], )      参数说明如下。   ① start(可选):整数,指定序列的起始值,默认为0。   ② stop:整数,指定序列的结束值,但不包括该值。   ③ step(可选):整数,指定步长(序列中相邻整数之间的差),默认为1。   举例:      range(10):[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]   range(1,10):[1, 2, 3, 4, 5, 6, 7, 8, 9]   range(1,10,2):[1, 3, 5, 7, 9]      4. 常见for循环应用方式   遍历字符串的字符:      word = "Python"   forch in word:    print(ch)      遍历数字序列:      for number in range(10):    print(number)      for number in range(1, 10):    print(number)      for number in range(1, 10, 2):    print(number)      遍历列表中的元素:      university = ["CCMU", "PKU", "THU"]   for u in university:    print(u)      遍历字典的键:      university = {"CCMU":1960, "PKU":1898, "THU":1911}   for key in university.keys():    print(f"{key}: { university.get(key }")      遍历字典的键和值:      university = {"CCMU":1960, "PKU":1898, "THU":1911}   for key, value in university.items():    print(f"{key}: {value}")      【例3-8】 求1~100的整数之和。   【任务实现】   任务分析:由于是从1开始的整数序列且间隔为1,所以可以用rang(1,101)的整数序列来进行循环累计求和。具体程序代码如图3-14所示。   【例3-9】 求1~20的偶数之积。   【任务实现】   任务分析:由于是从2开始的整数序列,且间隔为2,所以可以用rang(2, 21, 2)的整数序列来进行循环累计求积。具体程序代码和运行结果如图3-15所示。 图3-14?1~100的整数之和 图3-15?1~20的偶数之积   【例3-10】 制作如图3-16所示的九九乘法表。 图3-16?九九乘法表效果   【任务实现】   任务分析:九九乘法表共9行从1~9,可用 for 循环控制乘法表的行数,这为外层循环;在每一行内有9列,也从1~9,在这内部for循环用于每一行中的列。   在内层循环中计算两个数的乘积,使用print()函数打印乘法表的一行。“end="\t"”用于在输出时使用制表符分隔每个乘法表条目,使其看起来更整齐。具体程序代码如图3-17所示。 图3-17?九九乘法表程序实现   【例3-11】 根据一条单链上的碱基序列,给出对应的互补链上的碱基序列。A-T、G-C,如果不是这四个字母,用*代替。   在DNA中,碱基之间存在互补关系,这是DNA双螺旋结构的重要特点之一。碱基互补意味着一种碱基的存在总是伴随着另一种碱基的存在,它们通过氢键结合在一起。在 DNA 中,碱基之间的互补关系如下: * 腺嘌呤(Adenine,简写为 A)与胞嘧啶(Cytosine,简写为 C)是互补碱基。 * 鸟嘌呤(Guanine,简写为 G)与胸腺嘧啶(Thymine,简写为 T)是互补碱基。   【任务实现】   任务分析:由于碱基序列是字符串,所以可以用for循环依次处理每个字符。碱基序列有四种字符,所以要针对不同的字符分类进行处理,适合使用match-case多分支结构。   具体程序代码如图3-18所示。 图3-18?碱基互补链 拓展与思考   1965年9月17日,以王应睐为首的中国科研团队,历时6年完成了结晶牛胰岛素的全合成,这是世界上第一个人工合成的蛋白质。人工合成结晶牛胰岛素的成功,有力地证明了蛋白质的一级结构决定其高级结构的科学论断。 ??人工合成牛胰岛素凝聚了中国老一辈科学家的智慧,倾注了广大科研人员的心血和汗水。老一辈科学家们的艰苦奋斗、团结协作精神,对“科学强国梦”的执著追求,对科学真理的不懈探索、严谨求实的科学态度,淡泊名利、乐于奉献的精神让人敬佩。 3.3.2 条件循环:while循环   条件循环又称为while循环。while循环也是一种先判断后执行的循环结构。   1. 语法格式   while循环的语法格式如下:      while <条件表达式>:    <循环体>      2. 说明   <条件表达式>:条件表达式的值为布尔型(bool),真为True,假为False。此外,Python程序语言指定任何非0和非空(Null)值为真(True),0 或者Null为假(False)。所以,有时候可以看到while True或者while 1 这样的永远为真的判断条件。   <循环体>:当在条件表达式为真时所执行的程序语句。循环执行持续到条件表达式为假或遇到break语句时才结束循环,所以要注意循环变量的变化或循环条件结束的条件,否则容易产生“死循环”。此外,循环体中的一部分语句也可以使用循环嵌套。   while循环结构的流程图如图3-19所示。 图3-19?while循环结构的流程图   【例3-12】 用while循环改写例3-8的程序,实现1~100的整数之和。   【任务实现】   任务分析:在for循环中,系统会自动遍历每个元素,但在while循环中,循环条件中的循环变量值是不会自动变化的,所以要特别注意循环条件中循环变量的变化设置。   具体程序代码如图3-20所示。 图3-20?用while循环计算1~100整数和   【例3-13】?依次输入多个数据,直到输入“q”表示结束。将所输入的数据(不包含“q”字符)存为列表,打印输出时数据用逗号隔开。   【任务实现】   任务分析:可以采用循环方式接收依次输入的数据并保存,要考虑除了“q”字符之外才可保存下来。打印输出要考虑最后一个数据末尾不加逗号。   具体程序代码和运行结果如图3-21所示。   【思考题】   在接收数据时,用了两次判断,是否有改进方法只判断一次? (a)程序代码 (b)运行结果 图3-21 依次接收多个数据保存并打印输出   【例3-14】 现已有5位测试者的基本数据(见表3-1),依次计算这些学生的基本代谢率及每日能量消耗。 表3-1?测试者基本数据 编号 性别 (女=0,男=1) 体重 /kg 身高 /cm 年龄 /岁 平日活动强度 (分类1~5,见例3-4) 202301 0 55.5 165 18 2 202302 1 80.5 185 18 4 202303 0 50.2 161.3 23 1 202304 1 72.3 175.4 19 3 202305 1 76.6 178.5 20 5      【任务实现】   任务分析:涉及多位测试者,可用循环遍历实现。具体程序代码和运行结果如图3-22所示。   【思考题】   在打印输出结果时,把“性别”的数据0或1改为“男”或“女”,把“平日活动强度”的数字数据改为对应的文字描述。      # 构建数据集列表:性别,体重,身高,年龄,平日活动强度   data = list()   data.append([202301,0, 55.5, 165, 18, 2])   data.append([202302,1, 80.5, 185, 18, 4])   data.append([202303,0, 50.2, 161.3, 23, 1])   data.append([202304,1, 72.3, 175.4, 19, 3])   data.append([202305,1, 76.6, 178.5, 20, 5])      # 变量赋初值   BMR = 0 #基础代谢率   TDEE = 0 #每日能量消耗   result = dict() # 保存所有测试者数据的集合,如:{202304:{"data":[], BRM:, TDEE: },...}      # 输出结果显示的表头   print(f"{'编号':^4}{'性别':^4}{'体重':^2}{'身高':^8}{'年龄':^4}{'平日活动强度':^8}{'基础代谢率'}{'每日能量消耗':^8}")      # 遍历所有测试者数据,并计算每一位测试者的BMR和TDEE   i = 0 #循环变量赋初值   while i 8844.43: # 超过珠峰高度就停止循环    break    else:    hd *= 2 # 对折一次厚度翻倍    n += 1 # 对折次数加1   print(f"纸对折{n}次后的厚度为{hd:.2f}米,超过了珠穆朗玛峰。") (a)程序代码 (b)运行结果 图3-25?循环接收数据 拓展与思考   “合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下”。一张0.1毫米厚的纸,如果足够大,则对折27次以后就能超过珠穆朗玛峰的高度。所以,只要我们不断努力,假以时日,也会终有所成的。      【例3-17】 查找某测试者是否在测试集中。   【任务实现】   任务分析:可以采用for循环来遍历数据集,当遇到所要查找的测试者编号时使用break结束循环。具体程序代码和运行结果如图3-26所示。   numbers = [202301, 202302, 202303, 202304, 202305]   target = eval(input('请输入要查找的测试者编号:'))   index = 0      fornum in numbers:    if numbers[index] == target:    print(f"找到测试者:{target},序号为:{index + 1}。")    break    index += 1      print("查找结束。") (a)程序代码 (b)运行结果 图3-26?查找某测试者   【思考题】   在输出结果时,如果没有找到该患者数据时,如何实现对应的输出说明? 3.4.2 结束当次循环:continue   continue语句用于跳过当前循环迭代中的剩余代码,并回到循环的开始,继续执行下一次迭代。从而实现在不终止整个循环的情况下,跳过某些迭代步骤。   continue用来结束当前当次循环,即跳出循环体中后面尚未执行的语句,但不跳出当前循环。使用continue语句可以减少代码重复和逻辑嵌套,从而提高代码效率。   循环-continue结构的流程图如图3-27所示。   【例3-18】 输出10~50中的不能被7整除的整数。   【任务实现】   任务分析:依次判断每个数,当某数能被7整除则不输出此数,继续下一次循环。   具体程序代码和运行结果如图3-28所示。      for x in range(10,50):    if x % 7 == 0:    continue    print(x, end=' ') (a)程序代码    (b)运行结果 图3-28?输出10~50中的不能被7整除的整数   【思考题】   如果将程序中的continue改为break,则输出结果是什么?   【例3-19】 从患者信息列表中,显示年龄大于60岁的老年患者信息。   【任务实现】   具体程序代码和运行结果如图3-29所示。 图3-29 显示年龄大于60岁的患者信息 3.4.3 else语句   在Python中,else语句除了可以和if一起使用外,也可以和for或while循环一起使用。else语句提供了一种在循环正常结束时执行特定代码的方式。   1. 语法格式   else语句的语法格式如下:      for <循环变量> in <遍历对象>:    <循环体>   else:    <语句块> 或      while <条件表达式>:    <循环体>   else:    <语句块>