第3章 程序控制结 构 学习目标: .学会用传统流程图和N-S流程图表示问题求解的算法。 .学习并掌握选择结构的流程,能熟练应用单分支、双分支、多分支和嵌套分支的if 语句编写程序。 .学习并掌握循环结构的流程,能熟练使用while和for语句编写程序。 .学习并掌握循环的退出机制,能熟练应用break和continue语句。 .学习并掌握循环的嵌套,能熟练应用多重循环解决较复杂的问题。 3.控制结构概述 1 1.处理模式 3.1 从实际中可发现,人类处理问题的方式具有某些固定的模式化特征。下面举个生活 中的例子加以说明。 【例3-1】生活中的处理现象。 小明早上起床,洗漱完毕,吃些早点,然后准备去学校。走到门口,准备像往常一样穿 上皮鞋,但想到今天有体育课,就穿了运动鞋去学校。放学回家,吃完晚饭,休息一会儿开 始写作业。今天只有语文作业,但老师布置了20 道相同的抄写题,小明没有办法,只有一 道一道地做,直到全部做完,再去睡觉。 从上面的例子不难看出,小明在这一天中的行为方式具有一些明显特征。如“早上起 床、洗漱、吃早点”和“放学回家、吃晚饭、休息、写作业”等一系列的活动是按部就班的,按 顺序一步步地完成的。这是一种“顺序”特征。 走(“) 到门口,准备像往常一样穿上皮鞋,但想到今天有体育课,就穿了运动鞋去学校”, 小明在穿鞋的问题上做了个判断,根据当前情况决定穿什么鞋。如果没有体育课,他会穿 皮鞋。这反映出一种“选择”特征。 “老师布置了20 道相同的抄写题,小明没有办法,只有一道一道地做,直到全部做 完”,这里明显反映出“重复”和“循环”的特征。 生活中还可以举出很多类似的例子,虽然具体情况不同,但在处理流程上都表现出 “顺序”“选择”或“循环”的特征。可以这样说,任何问题都是按照某些特定的处理模式来 进行处理的。人类按照这样的方式处理问题,计算机其实和人类处理问题的方式一样,但 计算机要对这些处理方式进行具体、精确的描述,形成“算法”,并让处理器按照算法执行, 从而完成问题的处理。 3.2 算法的结构化表示 1. 问题的处理一般表现为顺序、选择和循环3种模式,算法要采用相应的方法将各种处 理模式表示出来,常用的表示方法有自然语言、流程图、伪代码等方式。 本节只介绍算法的流程图表示方式,因为流程图通俗易懂,能很好地反映算法的“结 构性”。流程图有两种:一种是传统流程图;另一种是N-S流程图。下面分别介绍。 1. 传统流程图 传统流程图用一系列图形、流程线来描述算法。传统流程图的基本图形元素如图3-1 所示。 图3-1 传统流程图的基本图形元素 应用上述图形元素,顺序、选择和循环表示的3种处理模式如图3-2所示。 图3-2 传统流程图表示的3种处理模式 【例3-2】将例3-1的处理流程用传统流程图表示。 根据前面的分析,例3-1所举的生活中的例子能较容易地用传统流程图表示,如图3-3 所示。 从图3-3可以看到,用传统流程图表示的算法逻辑清楚、易懂,结构性较好。但缺点 是,一旦算法复杂,则绘制比较麻烦,尤其是流程线若存在过多,会导致算法的结构清晰度 变差。下面介绍一种结构性更好的流程图表示形式。 第 3 章程序控制结构 53 图3-3 例3-1的传统流程图 2.N-S流程图 1973年,美国的计算机科学家Isi和B.n提出了一种新的流程图形 .NaShneiderma 式,在这种流程图中把流程线完全去掉了,全部算法写在一个矩形框内,在框内还可以包 含其他框,即由一些基本的框组成一个较大的框。这种流程图称为N-S流程图(以两人 名字的头一个字母组成),这种流程图能非常清晰地反映算法的结构性。图3-4用N-S流 程图表示顺序、选择和循环结构。 图3-4 N-S流程图表示的3种处理模式 【例3-3】将例3-1的处理流程用N-S流程图表示成如图3-5所示的形式。 从图3-5可以看出,相对于传统流程图,用N-S流程图表示的算法结构更清晰,更能 体现算法的结构性质。 54 Python 语言程序设计基础教程 第3 章 程序控制结构 55 图3-5 例3-1的N-S流程图 3.1.3 算法的语言表示 流程图能形象地以“结构化”的方式展示算法,但遗憾的是,无论是传统流程图,还是 N-S流程图,它们表示的算法计算机都不能识别执行,因为计算机只能理解用计算机语言 (程序设计语言)所表示的算法。流程图已经很好地以结构性的方式将算法表示出来,只 要掌握了某种程序设计语言的语法,就能很方便地用该种语言将算法进行精确的表示。 本书讲述的是Python语言,所以都是用Python语言来表示算法。在各种处理结构中, 顺序结构是最简单、也是最常用的结构形式,前面章节中的大部分例子都是顺序结构的, 下面从流程图到语言算法的实现角度再对顺序结构加以说明。 【例3-4】 任意输入两个整数到变量x、y中,将x、y中的数据交换并输出。 图3-6 例3-4的N-S流程图 经简单分析,可画出如图3-6所示的N-S流程图。 按照该流程图,利用Python语言实现的程序如下: #liti3-4-1.py x,y = eval(input('任意输入两个整数(用逗号间隔):')) x,y = y,x #交换x、y 的值 print('x={0},y={1}'.format(x,y)) 这种实现方式代码很精炼,但该例也可以用如下方式实现。 #liti3-4-2.py x,y = eval(input('任意输入两个整数(用逗号间隔):')) t = x #用变量t 来交换x、y 的值 x = y 56 Python 语言程序设计基础教程 y = t print('x={0},y={1}'.format(x,y)) 两种方法各有特点,读者可自行理解、比较,并上机练习加以体会。 从本节可以看出,算法无论是用流程图、编程语言还是其他的方式来表示,核心都是 结构化的思想,即用各种流程控制结构来进行算法的设计和细化。具体地说,就是在编程 前先对问题进行分析,得出问题的基本解决方案模型,再按结构化的思想对解决方案进行 算法的组织和设计,直到给出算法的完整处理步骤,最后用编程语言实现该算法。 顺序结构是一种最简单的流程控制结构,本章后面的内容将依次对选择结构和循环 结构进行详细介绍。 3.2 选择结构 选择结构也称为分支结构,用于实现根据条件处理不同的问题。选择结构可以分为 双分支、单分支、多分支以及嵌套的分支结构等类型。 3.2.1 双分支结构 双分支结构是一种最常见的分支结构,N-S流程图如图3-7所示。 图3-7 双分支结构的N-S流程图 对应的Python语句为 if <条件>: 语句块1 else: 语句块2 执行双分支语句时,当条件为True时执行语句块1,条件为False时执行语句块2; 语句块1和语句块2只能执行一个,执行完某一个即结束了该分支结构的执行。注意,if 和else后面都要加上冒号,语句块1和语句块2两个分支都要有一致的缩进。 条件表达式是实现选择结构或循环结构不可缺少的部分,条件表达式可以用关系运 算符、逻辑运算符、成员运算符、身份运算符等来实现,如1<x<10、a==b、x>yanda! =b、xinls、aisb等。注意,赋值运算符=不能出现在条件表达式中,不能和==运算符 混淆。 【例3-5】 输入成绩grade,分两种情况考虑,低于60分输出“不合格”,60分以上输 出“合格”。 根据问题描述,可以得出要用双分支的选择结构来表示处理步骤,对应的Python程 序如下。 #liti3-5-1.py grade = eval(input('输入成绩:')) 第3 章 程序控制结构 57 if grade<60: print('不合格') else: print('合格') 程序运行结果如下: 输入成绩:80 合格 再次运行该程序: 输入成绩:50 不合格 在Python中,双分支结构还可以用一种更简洁的形式表示。Python提供了一个三 元条件运算符,其构造的表达式可以实现与双分支结构相似的效果。语法为 <表达式1> if <条件> else <表达式2> 当条件为真时,该三元表达式的值取表达式1的值,否则取表达式2的值。这种表达 式很容易产生误解,认为就是选择语句。其实在此处的if…else…不是用于表示选择结构 语句,而是作为一种特殊的三元运算符,用于构造一种特殊的表达式。因此,例3-5也可 以表示如下: #liti3-5-2.py grade = eval(input('输入成绩:')) print('不合格' if grade<60 else '合格') 可以通过下面的例子进一步理解三元条件表达式: >>> a = 2 >>> a if a!=0 else '非法' 2> >> a = 0 >>> a if a!=0 else '非法' '非法' >>> x = eval(input('x=')) x=3 >>> y = eval(input('y=')) y=5 >>> x if x>y else y #等价于max(x,y) 5 3.2.2 单分支结构 单分支结构是一种特殊的选择结构,N-S流程图如图3-8所示。 58 Python 语言程序设计基础教程 图3-8 单分支结构的N-S流程图 对应的Python语句为 if <条件>: 语句块 执行单分支语句时,当条件为True时执行语句 块,条件为False时什么都不执行,直接结束该单分支 语句。 【例3-6】 输入成绩grade,对成绩分如下4种情况考虑。若成绩为[0,60),输出 “差”;成绩为[60,70),输出“中”;成绩为[70,80),输出“良”;成绩为[80,100],输出“优”。 该例可用多种方法解决,此处用单分支结构解决,学了后面的多分支和分支嵌套后, 对该例再分别用其他方法实现,并在不同方法间进行比较,总结不同结构的特点。该例用 单分支结构实现如下: #liti3-6.py grade = eval(input('输入成绩:')) if 0<=grade<60: print('差') if 60<=grade<70: print('中') if 70<=grade<80: print('良') if 80<=grade<=100: print('优') 程序运行结果如下: 输入成绩:50 差 多次运行程序,输入位于不同区间的分数,从结果看,可验证该程序是正确的。但仔 细分析,程序存在一个问题。如上面程序运行所示,输入成绩50,输出“差”。因为成绩满 足条件“0<=grade<60”,所以执行语句print('差')。但输出“差”后,程序并没有结束,还 会依次执行后面的3个单分支语句。这3个单分支语句的执行是没有必要的,因为当前 “0<=grade<60”的值为True,则条件“60<=grade<70”“70<=grade<80”“80<= grade<=100”的值肯定是False。但为什么后面3个if语句也会执行呢? 因为这4个单 分支if语句是各自独立的、并列的语句,它们之间是一种顺序结构,无论自身条件是真还 是假,对别的语句都不构成任何影响。即不论输入的是什么数,这4个if语句都会无条件 执行。显然这是一种不好的现象,程序运行中做一些不必要的运算,不但浪费了处理器的 时间,同时也降低了程序的运行速度。所以程序的好坏不能只从结果来看,还要从程序的 结构是否合理、精巧来判断。下面的多分支结构能很好地解决这个问题。 3.2.3 多分支结构 多分支结构的语法格式如下: 第3 章 程序控制结构 59 if <条件1>: 语句块1 elif <条件2>: 语句块2 .e lif <条件n-1>: 语句块n-1 [else: 语句块n] 从多分支结构的语法可以看出,当多分支结构执行时,会从上到下对条件依次判断, 一旦碰到成立的条件,则转去执行对应的分支语句块,然后结束整个多分支结构的执行, 不会对后面的条件再进行多余的判断。else子句是可选的,若else子句存在,则当前面的 条件都不成立时,执行else下面的语句块。因此,从结构特点和执行效率来看,多分支结 构是实现多种情况(3个以上)处理的最佳方式。 【例3-7】 对例3-6用多分支结构实现。 用多分支结构实现的程序代码如下: #liti3-7-1.py grade = eval(input('输入成绩:')) if 0<=grade<60: print('差') elif 60<=grade<70: print('中') elif 70<=grade<80: print('良') elif 80<=grade<=100: print('优') 上述程序以多分支的方式很好地解决了该问题,读者应将该例和例3-6的实现进行 比较,仔细体会两种方式的不同。 该程序还可以进一步优化。因为多分支是一个完整的独立结构,其中的多个条件是 按先后依次判断的,因此条件可以简化。例如,“60<=grade<70”可以改为“grade< 70”,“70<=grade<80”可以改为“grade<80”;最后一个elif分支可以用else取代,不需 要再判断,因为若前面3个条件都不成立,则分数一定是在80以上的。因此,程序可修改 如下: #liti3-7-2.py grade = eval(input('输入成绩:')) if 0<=grade<60: print('差') elif grade<70: print('中') elif grade<80: 60 Python 语言程序设计基础教程 print('良') else: print('优') 程序代码简洁,提高了可读性,但经过测试,发现修改后的程序存在问题。 输入成绩:-5 中 输入成绩:110 优 修改后的程序代码虽然简洁了,但忽视了对边界数据的检测,导致程序不能有效处理 小于0或大于100的数,从而出现了错误的结果。程序不正确,再怎么追求代码的简洁都 是没有任何意义的! 难道这个程序只能采用原来的写法,不能“鱼与熊掌兼得”吗? 其实, 只要先对数据的合法性进行判断,程序的正确性和简洁性是可以兼得的。下面要介绍的 嵌套分支结构就能很好地解决这个问题。 3.2.4 嵌套分支结构 一个分支结构完全包含了另一个分支结构,就形成了分支结构的嵌套。嵌套分支结 构的一般语法如下: if <条件1>: . if <条件2>: 语句块2 [else: 语句块3] . else: . if <条件4>: 语句块4 [else: 语句块5] . 上述只是嵌套分支结构的一般情况,实际中的嵌套情况可以根据具体问题灵活变化, if分支或else分支中不一定都要有嵌套,并且嵌套的层数没有限制,嵌套的结构里面还可 以继续嵌套。 【例3-8】 对例3-7用嵌套的分支结构实现既强健又简洁的程序。 在3.2.3节中,修改后的程序缺少对边界数据的检测,导致程序运行不稳定。解决的 办法是先安排一个双分支结构对输入数据的合法性进行判断,若合法则在内部嵌套一个 多分支结构对每种情况进行处理,否则输出数据非法的提示信息。相应程序如下: 第3 章 程序控制结构 61 #liti3-8-1.py grade = eval(input('输入成绩:')) if 0<=grade<=100: if grade<60: print('差') elif grade<70: print('中') elif grade<80: print('良') else: print('优') else: print('成绩错误') 程序运行结果如下: 输入成绩:-5 成绩错误 输入成绩:110 成绩错误 输入成绩:88 优 上述程序用带有“0<=grade<=100”条件的选择结构对数据的合法性进行检测,若 合法则在if分支中安排一个多分支结构继续处理。由于外部限定了合法数据的范围,内 部嵌套的多分支结构的条件可以进一步简化为“grade<60”“grade<70”“grade<80”等。 这样的解决方案,不但保证了程序的正确性,同时程序代码也不失简洁、结构清晰的特点。 解决该问题的思路稍做改变,还可以写出以下结构不同、但功能一样的程序: #liti3-8-2.py grade = eval(input('输入成绩:')) if 0<=grade<=100: if grade<60: print('差') else: if grade<70: print('中') else: if grade<80: print('良') else: print('优') else: print('成绩错误') 上面使用的是if语句的嵌套,下面采用的是多分支的if语句,结构更清晰、更容易 62 Python 语言程序设计基础教程 理解。 #liti3-8-3.py grade = eval(input('输入成绩:')) if grade<0 or grade>100: print('成绩错误') elif grade<60: print('差') elif grade<70: print('中') elif grade<80: print('良') else: print('优') 分支结构是一种常用且重要的处理控制结构,可分为单分支、双分支、多分支、嵌套分 支等多种类型。初学者应多采用一题多解的方式,因为该方式能使初学者快速、深入把握 各种算法处理结构,并达到灵活运用的目的。 3.2.5 选择结构综合举例 【例3-9】 任意输入3个整数a、b、c,按从大到小降序排列。 先比较a和b,保证a≥b;再比较a和c,保证a≥c,此时a是三者中的最大数;最后比 较b和c,保证b≥c。经过这3步处理,a、b、c已降序排列。这3步对应到3个单分支结 构,相应程序如下: #liti3-9-1.py a = int(input('a=')) b = int(input('b=')) c = int(input('c=')) if a<b: a,b = b,a if a<c: a,c = c,a if b<c: b,c = c,b print("降序结果:",a,b,c) 程序运行结果如下: a=3 b=8 c=5 降序结果: 8 5 3 第3 章 程序控制结构 63 上述程序采用了Python语言特有的交换方式,代码比较简练。该程序还可以进一 步简化。在a、b、c基础上创建列表[a,b,c],利用内置函数sorted()对该列表进行降序 排列,返回一个降序排列的列表,再对该降序列表进行多重赋值操作,将元素依次赋给变 量a、b、c并输出。相应程序如下: #liti3-9-2.py a = int(input('a=')) b = int(input('b=')) c = int(input('c=')) a,b,c = sorted([a,b,c],reverse=True) print('降序结果:',a,b,c) 可以看到,程序的Python味道越来越浓,代码也越来越精练。这是否已是该问题的 终结版了? 回答是否定的,还有更简练的,程序如下: #liti3-9-3.py a,b,c = sorted(eval(input('输入3 个整数(逗号间隔):')),reverse=True) print('降序结果:',a,b,c) 程序运行结果如下: 输入3 个整数(逗号间隔):5,8,3 降序结果: 8 5 3 此处只有两行代码。input()函数返回一个由逗号间隔的3个整数构成的字符串, 如"3,8,5"。eval()函数相当于将字符串两端的引号去掉,得到表达式的原本意义。 Python中,表达式3,8,5表示一个元组,则eval("3,8,5")得到元组(3,8,5)。再用 sorted()函数对该元组进行降序排列sorted((3,8,5),reverse=True),得到列表[8,5, 3]。最后将排序得到的列表进行多重赋值,将其中的元素依次赋给变量a、b、c,得到所需 结果。 【例3-10】 输入年份,判断是否为闰年。符合以下两个条件中的任何一个都是闰 年:①能被400整除;②能被4整除但不能被100整除。 分析角度不同,可以写出不同的程序。 方法一:使用多分支结构,程序代码如下: #liti3-10-1.py y = int(input('输入年份:')) if (y%400==0): print('是闰年') elif (y%4==0 and y%100!=0): print('是闰年') else: print('不是闰年') 读者也可以将该问题用嵌套的分支结构实现,多分支结构和嵌套分支结构在某些情 64 Python 语言程序设计基础教程 况下是等价的。 方法二:使用双分支结构,程序代码如下: #liti3-10-2.py y = int(input('输入年份:')) if (y%4==0 and y%100!=0) or (y%400==0): print('是闰年') else: print('不是闰年') 将两个条件用逻辑运算符or连接起来,构成一个完整的判断闰年的条件表达式,程 序代码就简短了。 其实还有别的方法,例如通过内置模块calendar中的isleap()函数来实现闰年的判 断,程序更易编写,感兴趣的读者可以自行尝试。 【例3-11】 输入三角形的3条边,判断其构成的是等边三角形、等腰三角形、直角三 角形,还是普通三角形。 首先对输入的3边进行判断,能否构成三角形,能则再判断是4种三角形里面的哪一 种,否则输出错误提示。相应程序如下: #liti3-11-1.py a,b,c = eval(input('输入3 条边(逗号间隔):')) if a+b>c and a+c>b and b+c>a: if a==b==c: print('等边三角形') elif a==b or a==c or b==c: print('等腰三角形') elif a**2+b**2==c**2 or a**2+c**2==b**2 or b**2+c**2==a**2: print('直角三角形') else: print('普通三角形') else: print('不能构成三角形') 上述程序能全面、正确地解决该问题,但问题就是有些条件太长了,程序看上去不简 洁。有没有办法将条件变短呢? 其实只要对输入的3边先进行排序(升序),后面的条件 就可以大大简化,为此程序的第一条语句可以改为a,b,c=sorted(eval(input('输入3条 边(逗号间隔):')))。因为a、b、c升序排列了,则判断能否构成三角形只须判断a+b>c 即可,且a、b、c升序排列后,a+c>b和b+c>a是绝对成立的。类似地,判断等边三角形 只须a==c;判断等腰三角形只须a==borb==c;判断直角三角形只须a**2+b**2== c**2。因此,修改后的程序如下: #liti3-11-2.py a,b,c = sorted(eval(input('输入3 条边(逗号间隔):'))) if a+b>c: 第3 章 程序控制结构 65 if a==c: print('等边三角形') elif a==b or b==c: print('等腰三角形') elif a**2+b**2==c**2: print('直角三角形') else: print('普通三角形') else: print('不能构成三角形') 经过优化,程序变得简洁,可读性也更好了,这样的程序不也反映出一种美吗? 程序的确看起来清爽了很多,但这个程序是否已完美地解决了这个问题呢? 仔细分 析,还是能发现美中不足的地方。例如,若输入的3条边能构成一个等腰直角三角形,按 照上面的程序却只能输出“等腰三角形”的判断,漏掉了“直角”这个重要特征,这显然不合 适,输出“等腰直角三角形”的判断才是最适宜的。但当前这个程序做不到,如何改进呢? 感兴趣的读者可以自行思考。 所以,编程不能只满足于一蹴而就,后期对程序的完善也非常重要,这一点初学者尤 其要注意。只有对程序结构、算法的孜孜以求,才能进一步激发编程的兴趣,发现编程的 魅力所在,并不断提高自身的程序设计水平。 3.3 循环控制结构 循环即往复回旋,指事物周而复始地运动或变化。在程序设计中,通过循环,可以使 一组语句重复执行多次。例如,要计算100以内的偶数和,可以使用一个变量来存储偶数 的和,假设使用变量sum 来保存其和,在求和之前使sum 的值为0,即sum=0。假设使 用变量i来遍历[2,100)的偶数,i每遍历一个偶数,使语句sum=sum+i执行一次;当i 遍历完[2,100)的偶数后,sum 中就保存了100以内的偶数和。在Python语言中通过for 或while可以实现循环控制。 3.3.1 while循环语句 在Python中,while循环语句的语法格式如下: while 循环条件: 循环体语句 只要循环条件成立,while语句中的语句序列就会一直执行,这个语句序列叫作 while语句的循环体语句。 while循环语句的执行过程如下。 66 Python 语言程序设计基础教程 (1)计算循环条件,若条件为真,则执行步骤(2);否则结束循环。 (2)执行循环体语句,执行完后继续执行步骤(1)。 while循环语句的执行过程可以用图3-9表示。 【例3-12】 用while循环语句,编程求100以内(不包括100)的偶数和。 分析:使用了sum 来保存偶数和,使用了变量i来遍历2~98的偶数。变量sum 和i 在进入循环之前都要对其进行初始化,即在没有求和之前,应使sum 的值为0。100以内 最小的非零偶数为2,因此i=2,即表示i从最小的2开始遍历,一直要遍历到98,所以循 环的结束条件是i<100。每循环一次累加一个偶数,并计算出下一次要累加的偶数。程 序的算法流程图如图3-10所示,程序代码如下: #liti3-12.py sum=0 i=2 while i<100: sum+=i i=i+2 print("2+4+…+%d=%d"%(i-2,sum)) 图3-9 while循环语句的执行过程 图3-10 例3-12的算法流程图 程序运行结果如下: 2+4+…+98=2450 在本例中,请读者思考如下3个问题。 (1)while后面的循环条件能否改为i<=100? (2)在print输出中,为什么用i-2,而不是i? (3)在程序liti3-12.py中使用循环变量i,从2遍历到98,如果要让循环变量i从98 开始遍历到2,上述程序应如何修改? 【例3-13】 小明现有10000元准备存入银行,进行理财。目前银行三年以上的定期 年利率是2.75%,假设利率不变,可以利滚利,问至少存多少年后小明的账户余额可以 翻倍? 使用变量rate、bal、year来分别存储利率、账户余额和年份,在进入循环前给它们赋 题目要求的初值,当账户余额小于目标值(20000)时,计算下一年份的余额,并累加年份, 循环结束后输出所求的年份和账户余额。程序的算法流程图如图3-11所示,程序代码 如下: 第3 章 程序控制结构 67 图3-11 例3-13的算法流程图 #liti3-13.py rate=2.75 bal=10000 year=0 while bal<20000: year=year+1 bal=bal+bal*rate/100 print("year=%d,bal=%.2f"%(year,bal)) 程序运行结果如下: year=26,bal=20245.46 在本例中,请读者思考如下两个问题。 (1)程序中的循环条件能否改为bal≥20000? 如果改为bal≥20000,while的循环体 语句执行了多少次? (2)year的初值为什么是0,能否是1? 总结上述两个例题,使用while循环语句设计程序,需要注意以下事项。 (1)在进入循环前要给循环控制变量赋初值,如例3-12中的i和例3-13中的bal。 一般来说,循环变量的初值是循环开始的值,循环条件是用循环变量与终值进行比较。 (2)在循环体内至少要有一条语句能够改变循环变量的值,使之趋向循环结束条件, 否则,循环将永远不会结束,把永远不会结束的循环称为“死循环”。例如,把例3-12中的 程序代码修改如下: sum=0 i=2 while i<100: sum+=i print("2+4+…+%d=%d"%(i-2,sum)) 在PythonIDLE环境下运行上述程序,可以看到光标一直在闪烁,结果出不来,就是 因为上述程序有“死循环”。此时可按Ctrl+C组合键强行终止程序的运行,并修改程序。 (3)在格式上,循环条件后面一定要有冒号“:”,循环体语句一定要进行缩进,循环 结束后的第一条语句一定要与while对齐,否则程序运行时会出错。 3.3.2 for循环语句 Python中的for循环语句用于遍历可迭代对象中的每个元素,并根据当前访问的元 素做数据处理,其语法格式如下: for 变量in 可迭代对象: 循环体语句 for循环语句的执行过程是依次取可迭代对象中的每个元素的值,如果有,取出赋给 68 Python 语言程序设计基础教程 变量,执行循环体语句,否则循环结束。 for循环语句的执行过程可用图3-12表示。 【例3-14】 用for循环语句,编程求100以内(不包括100)的偶数和。 和例3-12一样,使用变量sum来保存偶数和的值,在求和之前赋初值为0,即sum=0, 再用循环变量i来遍历2~100的偶数(不包括100),每循环遍历一次,累加一个偶数。程 序的算法流程图如图3-13所示,程序代码如下: #liti3-14.py sum=0 for i in range(2,100,2): sum+=i print("2+4+…+%d=%d"%(i,sum)) 图3-12 for循环语句的执行过程 图3-13 例3-14的算法流程图 程序运行结果如下: 2+4+…+98=2450 在使用for循环语句时,如果需要遍历一个数列中的所有数字,则可以用range()函 数生成一个可迭代对象。程序中用了range(2,100,2),表示的就是从2开始,到100终止 (不包含100),步长为2的迭代对象。 【例3-15】 已知华氏温度与摄氏温度之间的转换关系:C=(5/9)*(F-32)。其 中,F为华氏温度,C为摄氏温度。编写程序,分别显示华氏温度0,10,20,…,100与摄氏 温度的对照表。 该程序的算法非常简单,流程图省略,程序代码如下: #liti3-15.py print("华氏温度\t 摄氏温度") for F in range(0,101,10): C=5/9*(F-32) print("%d\t\t%0.2f"%(F,C)) 程序运行结果如下: 华氏温度摄氏温度 0 -17.78 10 -12.22 20 -6.67 30 -1.11 40 4.44 50 10.00 第3 章 程序控制结构 69 60 15.56 70 21.11 80 26.67 90 32.22 100 37.78 程序print()函数使用了转义字符\' t',表示到下一制表位,一个制表位表示8字节宽 度,常用于控制输出对齐,详见第6章。 【例3-16】 已知list1=["Python","C++","Basic","Java"],用for循环实现,一行 输出一个元素。 程序代码如下: #liti3-16.py list1=["Python","C++","Basic","Java"] for ls in list1: #遍历列表list1 中的每个元素 print(ls) 程序运行结果如下: Python C++ Basic Java 使用for循环语句设计程序,需要注意以下事项。 (1)可迭代对象可以是列表、元组、字符串、集合和字典等序列数据,也可以是range 等可迭代函数。如果是字典,每次遍历时获取的是元素的键,通过键可以再获取元素的 值,代码如下: dict1={1:"Python",2:"C++",3:"Basic",4:"Java"} for d in dict1: print(d,":",dict1[d]) 程序运行结果如下: 1 : Python 2 : C++ 3 : Basic 4 : Java (2)在格式上,for后面一定要有冒号(:),循环体语句一定要进行缩进,循环结束后 的第一条语句要与for对齐,否则程序运行时会出错。 3.3.3 break语句 break语句用于跳出for循环或while循环,转到循环后的第一条语句去执行。如果 70 Python 语言程序设计基础教程 break用在多重循环中,则break语句只能跳出它所在的本层循环。 其语法格式如下: break 【例3-17】 从键盘输入一个正整数n,判断n是否是素数。 素数是指只能被1和它本身整除的数。可以使用反证法,用变量i遍历2~n-1,若 n能被某个i整除,则说明n不是素数,提前结束循环,此时i一定小于n,输出“不是素 数”,否则输出“是素数”。程序代码如下: #liti3-17.py n=int(input("请输入一个正整数:")) for i in range(2,n+1): if n%i==0: #如果n 能被i 整除 break #说明n 不是素数,跳出循环,此时i 小于n if i<n: print("%d 不是素数!"%n) else: print("%d 是素数!"%n) 程序运行结果如下: 请输入一个整数:16 16 不是素数! 再运行一次程序: 请输入一个整数:37 37 是素数! 上述算法是让n去除以2~n-1的每个整数,如果都不能整除,说明n就是素数。该 算法中当n是一个非常大的素数时,要执行n-1次循环,效率很低。为了提高效率,必须 减少循环的次数。是否可以不除到n-1,例如除到n/2或n即可判定n是否是素数,如 果可以,读者自行修改程序。 3.3.4 continue语句 continue语句用于结束本次循环并开始下一次循环,对于多重循环情况,continue语 句作用于它所在的本层循环。 【例3-18】 阅读下列程序代码。 程序代码如下: #liti3-18.py sum=0 while True: 第3 章 程序控制结构 71 n=eval(input('请输入一个整数(输入0 结束程序):')) if n==0: break if n%3!=0: continue sum+=n print("sum=%d"%sum) 运行该程序时,若依次输入15、20、35、40、45、50和0,则最后输出sum 等于多少呢? 在上面的程序中,循环条件设置为True,通常称这种循环为“永真循环”,即不可以通 过条件不成立退出循环。对于这种“永真循环”,在循环体中必然包含break语句退出循 环,否则将导致死循环,程序无法正常退出。该程序中,如果输入的值为0,则退出循环, 如果输入的值不是3的倍数,则结束本次循环,进行下一次循环。因此该程序的运行结果 为60。 3.3.5 else语句 在Python语言中,for循环和while循环可以有else分支语句。当for循环已经遍历 完可迭代对象中的所有元素或while循环的条件为False时,就会执行else分支中的语 句。也是就说,在for循环或while循环中,只要不是执行到break语句而退出循环的,如 果有else语句,就要执行else分支语句块。 带else分支的for循环的语法格式如下: for 变量in 可迭代对象: 循环体语句 else: 分支语句块 带else分支的while循环的语法格式如下: while 循环条件: 循环体语句 else: 分支语句块 【例3-19】 从键盘输入一个正整数,判断该数是否是素数。用带else分支的语句改 写例3-17中的程序代码。 程序代码如下: #liti3-19.py n=int(input("请输入一个正整数:")) for i in range(2,n): if n%i==0: print("%d 不是素数!"%n)