吃透Python-第 4 章 程序流程之循环
本章,我将围绕用于控制程序循环结构的 while 语句和 for 语句进行介绍。
循环
先判断后循环与先循环后判断
判断表达式和循环体
while 语句
for 语句和 range 函数
增量赋值运算符
递增计数
递减计数
计算 1 到 n 的和
break 语句和 else 代码块
continue 语句
无限循环
多重循环
使用 import 语句导入模块
使程序暂停运行(time.sleep 函数)
生成随机数(random.randint 函数)
猜数字游戏/猜拳游戏
自带电池
使用循环语句遍历
4-1 while 语句
程序流程中的循环结构应用了上一章介绍的分支结构。本节,我们会学习用于实现循环的 while 语句。
关于 while 语句
循环结构可以实现以下功能。
重复执行相同或相似的处理操作。
变更条件的同时重复执行处理。
重复执行处理直到某个条件成立。
本章最先实现的程序如代码清单 4-1 所示。该程序会读取两个整数的值,并以递增的方式输出这两个整数之间的所有整数的值(包括这两个整数)。
上面代码中读取整数并按升序对整数排列的部分与代码清单 3-33 相同。
▶ 如运行示例所示,从键盘读取 a 和 b 的值时,不论先读取 8 还是先读取 3,排序之后 a 都等于 3,b 都等于 8。
排序后,将 a 赋给 counter(运行示例中将 3 赋给了 counter)。
蓝色底纹部分称为 while 语句,是一个只在表达式求值为真时重复执行代码组的循环语句。
另外,在本书中,判断循环是否继续的表达式称为判断表达式,重复执行的代码组称为循环体。
▶ 循环(loop)就是重复的意思。
大家不要忘记上一章学过的,当执行的代码组由多行代码构成时,各代码行必须对齐缩进。此外,也可以像下面这样将代码全部写在一行中,不过我并不推荐这种写法。
图 4-1 代码清单 4-1 中的 while 语句的流程图
这个程序中 while 语句的流程图如图 4-1 所示。while 语句在 counter 的值小于等于 b 时重复执行循环体内的两个处理操作。
打印输出 counter 的值(和空格)。
计算 counter + 1 的运算结果并将值赋给 counter,
counter 的值仅增加 1。
程序流程进入 while 语句时,counter 的值是 3,所以屏幕输出了 3(和空格),随后 counter 的值更新为 4。
程序流程再次回到 while 语句的开头,判断是否继续循环。因为 counter 的值 4 小于 b,所以程序再次执行循环体。
程序就是这样不断重复相同操作的。
当 counter 的值显示为 8,然后又增加到 9 时,counter <= b 不再成立,while 语句结束。
虽然程序最终输出的数字是 8,但 while 语句结束时,counter 的值是 9。
在调用程序最后的 print 函数时,使用以下方式改写 print(),可以方便我们确认结果(chap04/list0401a.py)。
接下来计数时每隔一个数加 1。counter 的值的更新部分改写为以下形式(chap04/list0401b.py)。
递减计数
下面,我们来编写一个读取整数,并对整数递减计数到 0 的程序。具体如代码清单 4-2 所示。
注释内容为“n 减 1”的那行“n -= 1”,与进行减法运算后赋值的“n = n - 1”(基本)相同。
另外,变量的值每次只减少 1 称为递减(decrement),变量的值每次只增加 1 称为递增(increment)。
▶ 其他编程语言提供了递增运算符 ++ 和递减运算符 --,但 Python 没有这些运算符。
另外,increment 和 decrement 原本的含义分别是“增加”和“减少”,但在计算机领域,它们常用于表示“加 1”和“减 1”。
在二元运算符 +、-、*、@、/、//、%、**、>>、<<、&、^、| 后放置 = 所构成的分隔符称为增量赋值运算符(augmented assignment operator)(表 4-1)。
当运算符是 ★ 时,将 ★ 的运算结果赋给 a 的“a = a ★ b”与增量赋值“a ★ = b”(基本)相同。在编程时利用增量赋值有以下好处。
更简洁地表示运算
“n 减 1”不仅比“将 n 减 1 的值赋给 n”更简洁,而且这种形式对我们来说也更容易理解。
等号左边的变量名只需要写一次
在变量名较长或表达式较为复杂时,比如使用了后面介绍的“列表”或“类”等情况下,出现拼写错误的可能性较小,代码也更容易阅读。
等号左边只进行一次求值操作
使用增量赋值的一个好处就是等号左边只进行一次求值操作。
▶ 本节之所以多次使用“基本”这个词,是因为两种表达式其实仍然存在求值次数不同的区别,以及其他的不同点(7-1 节)。
表 4-1 增量赋值运算符(注意:增量赋值运算符在语法上不是运算符)
▶ 赋值运算符并不是真正意义上的运算符(1-2 节),与此相同,增量赋值运算符也不是运算符。另外,不可以在增量赋值运算符中间插入空白符号,比如 + = 和 >> = 之类的形式。
了解了增量赋值以后,我们从整体上来看一下代码清单 4-2。
该程序的 while 语句对变量 n 的值执行递减操作直至该值为 0。下面,我们一边看图 4-2,一边思考运行示例的情况。
图 4-2 代码清单 4-2 中 while 语句的流程图
最开始在调用 print 函数时,程序打印输出了从键盘读取的值 5(和空格),随后 n 的值递减为 4。
程序流程再次回到 while 语句的开头,判断是否继续循环。
因为变量 n 的值为 4,大于 0,所以在执行循环体后,程序会输出相应的内容并进行递减操作。
程序继续循环,直到打印输出 0 后 n 递减为 -1,while 语句的循环就此结束。
虽然程序最后输出的数字是 0,但是 while 语句结束时,n 的值是 -1。
另外,像运行示例 那样,如果读取的 n 不为正数,程序就会略过 while 语句(while 语句的循环体一次也没有执行),只输出换行符。
▶ n 原本应该只为正整数。改进后的程序如代码清单 4-4 所示。
计算 1 到 n 的和
代码清单 4-3 是使用了增量赋值运算符的程序示例,该程序计算了 1 到 n 的和。
例如,读取的整数 n 如果为 5,则程序会计算 1 + 2 + 3 + 4 + 5 的值,最终结果为 15。
1 和 2的流程图如图 4-3 所示,我们来看看这部分代码的行为。先来看一下程序概要。
1该部分是求和前的准备工作。用于存储求和结果的变量 sum 的值为 0,用于控制循环的变量 i 的值为 1。
2 变量 i 的值只要小于等于 n,程序就会在不断递增 i 的值的同时,重复执行循环体。程序总共重复了 n 次。
图 4-3 计算 1 到 n 的和的流程图
图 4-3 中右侧的表格汇总了在执行 while 语句中的判断表达式 i <= n(即流程图中◇的部分)时,变量 i 和变量 sum 的值的变化情况。我们可以一边对照这个表格,一边学习程序。
第一次执行判断表达式 i <= n 时,变量 i 的值和 sum 的值是 中设定好的值。此后,每进行一次循环,变量 i 的值就会递增,每次加 1。
因此,在执行判断表达式时,两个变量的值如下所示。
变量 sum …在执行判断表达式时已经求得的和
变量 i …下一次增加的值
比如,当 i 等于 5 时,变量 sum 的值为 10。这是 1 到 4 的和,是加 5 之前得到的值。
另外,当 i 的值大于 n 时,while 语句的循环才会结束,所以最后 i 的值是 n+1 而不是 n。
▶ 如表所示,如果 n 等于 5,while 语句结束时 i 等于 6,sum 等于 15。
▶ 该程序更为简洁的实现方法将在第 7 章讲解。
专栏 4-1 可以使程序暂停运行一段时间的 sleep 函数
代码清单 4-2 所示的程序进行了递减计数。对该程序进行修改后得到的代码清单 4C-1,会每隔 1 秒打印输出一次递减计数的结果。
这里使用的 time.sleep 函数是 time 模块内的函数,该函数根据 () 内指定的秒数暂停程序。
另外,开头的 import 声明和函数调用的形式是“名字 . 名字 ()”而不是“名字 ()”的原因,将在第 96 页进行粗略介绍,在第 10 章进行详细讲解。
else 代码块和使用 break 语句中断循环
在之前的例子中,不论是进行递减的程序还是计算 1 到 n 之和的程序,如果读取的值不为正数,程序就会输出奇怪的结果。
代码清单 4-4 修改了代码清单 4-3 的前半部分,使程序只从键盘读取正整数。
将读取的值赋给 n 的语句插入到了蓝色底纹部分的 while 语句中。该 while 语句的判断表达式就是单纯的 True。由于该判断表达式的结果为真,所以 while 语句会一直进行循环。这种循环称为无限循环。
break 语句
程序从键盘读取整数后,通过 if 语句判断 n 是否为正数。判断成立时执行的语句是前面我们没有见过的 break 语句(break statement)。
如图 4-4 所示,循环语句中的 break 语句一旦被执行,程序就会强行结束循环语句,进而跳出无限循环。
▶ 在 4-3 节讲解的“多重循环”中,如果执行 break 语句,该 break 语句所在的循环语句就会终止执行。
另外,如果读取的整数 n 小于等于 0,则 break 语句不会被执行,程序会再次开始循环执行 while 语句(提示输入“n 的值 :”后读取相应数字)。
else 代码块
在图 4-4 中,while 语句的末尾添加了 else 代码块。只有在 while 语句的循环没有因 break 语句强行结束时,else 代码块内的代码组才会被执行。
▶ 我们通过代码清单 4-6 来学习一下带有 else 代码块的 while 语句的示例。
图 4-4 while 语句、break 语句和 continue 语句
使用 continue 语句跳过循环内的处理操作
continue 语句(continue statement)和 break 语句相对应。如图 4-4 所示,程序执行循环语句中的 continue 语句后,跳过了循环体中后续代码的处理,程序流程回到判断表达式。
代码清单 4-5 是使用了 continue 语句的程序示例。
程序不断读取整数 n 的值,通过循环进行加法运算,计算出整数的总和。此时,程序进行了如下处理操作。
如果 n 等于 -9999,则程序停止读取。 …执行 break 语句
如果 n 小于等于 0,则不进行加法运算(只对正整数进行加法运算)。…执行 continue 语句
由于在 n 小于等于 0 时程序执行了 continue 语句,所以程序跳过了增量赋值 sum += n 的处理(于是,负数没有与 sum 进行加法运算)。
编写猜数字游戏(生成随机数和模块)
现在,我们来实践一下——编写一个猜数字的游戏。
数字范围是 1~1000,必须在 10 次以内猜中。错误输入小于 1 或大于 1000 的数字时,程序不会将其计入猜测的次数。
代码清单 4-6 为完成后的程序。
生成随机数和导入模块
如果正确答案每次都一样,就不能叫游戏了,所以我们要用到随机数(无法进行预测的数)。
程序一般不会内置生成随机数的功能,好在 Python 允许我们随时自行嵌入必要的功能。
嵌入功能1时使用的是 的 import 语句(import statement)。这里导入了 random 模块。
第 2 章提到函数是程序的零件,而模块则汇集了以函数为首的各种零件。
▶ 这里,我只简单地提了一下模块。关于模块、import 方法和模块内函数的调用方法等内容,我会在第 10 章详细介绍。
嵌入模块后,我们可以通过以下形式调用模块中的函数。
模块名.函数名(并列的实参)
该程序使用了 random 模块中的 randint 函数。如图 4-5 所示,random.randint(a, b) 生成并返回一个范围在 a~b 的随机数(从 a~b 中任意选取的一个整数)。
图 4-5 使用 random.randint 函数生成随机数
因此, 中将 1~MAX,即 1~1000 中的任意数字赋给变量 answer(程序每次运行得到的值都不同)。
该程序中的 while 语句在 stage 小于等于 MAX_STAGE,即小于等于 10 时进行循环(如果输入了错误的数字,stage 的值会递增)。
▶ 程序把待猜测数字的最大值 1000 和最大猜测次数 10 赋给变量,而且这些变量的名字使用了大写字母。这样就避免了在代码中插入幻数,同时数值的修改也变得更加容易。
3用于检查赋给变量 n 的值。如果它的值不在规定范围之内(小于 1 或大于 1000),程序执行 continue 语句后就会跳过 4 ~ 7 的代码(特别要注意程序会跳过 7中 stage 的递增操作)。
如果它的值在规定范围之内,程序则根据判断结果,选择执行以下操作。
读取的值 n 与待猜测的数字 answer 相比
如果相等:输出信息告知二者相等并强行结束 while 语句。 … 4正确
如果更大:输出“正确数字要小一些。” … 5不正确
如果更小:输出“正确数字要大一些。” … 6不正确
在猜错数字时, 7中的 stage 会递增。如果 stage 递增后的值超过 MAX_STAGE,即超过 10,可输入的次数达到上限,while 语句结束循环。
如果是在没有执行 break 语句的情况下结束 while 语句,程序就会执行 else 代码块。由于此时输入次数达到上限,所以程序会提示猜测数字失败并显示正确答案( 8)。
编写猜拳游戏
学习了随机数的生成方法后,我们再试着编写另一个游戏。代码清单 4-7 是一个猜拳游戏的程序。
该程序使用 0、1 和 2 分别表示石头、剪刀和布。计算机的出拳由随机数生成,玩家的出拳通过键盘读取。
如图 4-6 所示,计算机和玩家的出拳组合共有 9 种。针对这些组合, 2 使用了单一的表达式来计算胜负。
▶ 本节程序在循环语句中使用了循环语句(4.3 节介绍的多重循环结构)。
图 4-6 出拳组合和胜负判定
自带电池
自带电池(batteries included)是 Python 的特性之一。这个词组原本是指顾客在购买家用电器或电子产品时,产品会附赠电池(但电池并未内置在产品中)。
Python 中有许多零件。print 函数等内置函数一开始就被内置在了 Python 中,而 random.randint 这样的函数在导入后也能随时内置到程序中(图 4-7)。
图 4-7 自带电池
由各种企业和组织提供的非标准功能在必要时也可以引入程序中。这就好像游戏中的角色一样,可以随时升级,装备上喜欢的道具。
4-2 for 语句
与上一节讲解的 while 语句相同,for 语句(for statement)用于控制程序流程中的循环结构。本节,我们将学习 for 语句的基础知识。
关于 for 语句
用于控制循环的语句除了 while 语句,还有 for 语句。代码清单 4-8 是一个使用 for 语句按照指定的次数打招呼的程序。
首先来看 range(n)。该函数生成了 0, 1, 2, …, n-1 这种数字序列,即数字的“排列式”。
range(n) 表示的内容如下。
range(n) 大于等于 0 且小于 n 的整数按顺序排列后生成的数字序列
请注意,排列式的最后一个数字不是 n,而是 n-1。
▶ range 有范围、界限和排列等含义。
下面,我们来看 for 语句的行为。具体如下所示。
“for 变量 in 排列式 : 代码组”用于不断取出排列式中的值作为变量值,然后执行代码组,直到排列式中的所有数字被取出。
在运行示例中,n 等于 3,range(3) 生成了数字序列 0, 1, 2。程序流程如下所示。
程序执行 range(3) 后生成了数字序列 0, 1, 2(只在开始时执行 1 次)。
变量 i 取值为 0,执行代码组(调用 print 函数的语句)。
变量 i 取值为 1,执行代码组(调用 print 函数的语句)。
变量 i 取值为 2,执行代码组(调用 print 函数的语句)。
像变量 i 这种用于控制循环的变量,称为计数变量。
在计算机的世界中,一般从 0 开始计数,而我们人一般是从 1 开始计数的。代码清单 4-9 对程序进行了修改,使循环计数从 1 开始,循环 n 次。
程序输出的 No 值从“i”修改为了“i+1”。
传给 range 函数两个实参后,range 函数变为 range(a, b) 的形式。调用该函数会生成以下排列式。
range(a, b) 大于等于 a 且小于 b 的整数按顺序排列后生成的数字序列
请注意,排列式的最后一个数字不是 b,而是 b-1。
代码清单 4-10 使用该形式对程序进行了修改。
在运行示例中,n 等于 3,程序执行 range(1, 4) 后生成了数字序列 1, 2, 3。
本章最开始的程序,即代码清单 4-1,使用了 while 语句列举大于等于 a 且小于等于 b 的整数。
代码清单 4-11 组合使用了 for 语句和 range 函数对代码清单 4-1 进行了修改。
与使用 while 语句的程序相比,修改后的程序更加简洁。
▶ 在其他编程语言中,for 语句内用于计数的变量(本节程序中的 counter)仅可以在 for 语句中使用,而 Python 则不同,用于计数的变量在循环语句执行后仍然可以使用。
range 函数
本书已经讲解了 range 函数的两种调用方法,实际上还有一种。传给 range 函数 3 个实参后,range 函数变为 range(a, b, step) 的形式,调用该函数会生成以下数字序列。
range(a, b, step) 在大于等于 a 且小于 b 的整数中,每隔 step 个取出一个数字所形成的数字序列
请看代码清单 4-12 所示程序。
像运行示例 2那样,如果 step 是负数,程序就会生成从大到小排列的数字序列。
图 4-8 range 函数
▶ 理解 for 语句需要用到后面章节的知识,这里我简单讲解一下。以下内容可以在学完第 8 章之后再来阅读。本章使用数字序列(排列式)来代表可迭代对象(iterableobject)。在 for 语句中,(在数字序列的位置)除了可以使用 range() 表达式,还可以使用任意的序列类型(sequencetype),比如字符串等。
range(n) 生成的是一个可迭代对象,它存储了数字序列 0~n-1。
专栏 4-2 为什么用于计数的变量,其名称是 i 或 j
许多程序在控制 or 语句等循环语句时使用变量或 j。
这种用法最早可追溯到用于科学计算的编程语言 FORTRAN 的早期。在这种编程语言中,变量原则上是实数。但程序唯独会自动将变量名的开头字符是 i, j, …, n 的变量视为整数。因此,使用 i、j 等作为控制循环的变量是最简单的方法。
我们现在使用 for 语句编写几个程序。
列举奇数
代码清单 4-13 是一个读取整数后,输出小于等于该整数的正奇数(1、3 等)的程序。变量 i 的值从 1 开始每次增加 2。
列举约数
代码清单 4-14 是一个读取整数后输出该整数所有约数的程序。
在 for 语句中,变量 i 的值从 1 递增到 n。如果 n 除以 i 的余数为 0(n 能被 i 整除),则 i 是 n 的约数,程序输出 i 的值。
连续输出符号
代码清单 4-15 是一个读取整数后,按整数表示次数连续输出符号 * 的程序。
用于循环计数的变量,其名称使用了 _。变量名 _ 可以明确告知读程序的人该变量的值不在循环体中使用。
▶ 变量 _ 的值可以在循环体中被读取和使用。
else 代码块
与 while 语句相同,for 语句也可以在末尾添加 else 代码块。
使用 else 代码块的 for 语句只有在循环正常结束时(循环没有被 break 语句强行结束)才会执行 else 代码块中的代码组。
代码清单 4-16 为使用了 else 代码块的 for 语句的程序示例。
循环执行 for 语句,可以生成 n 个范围在 10~99 的随机数。
在程序运行过程中如果生成了 13,程序就会输出“根据条件终止循环。”,for 语句的循环会被 break 语句强行终止(程序没有输出 13)。因此,else 代码块没有被执行。
另外,如果程序从未生成 13,循环结束后程序就会执行 else 代码块,输出“随机数生成结束。”。
for 语句和遍历
本章讲解的 for 语句只进行了 n 次循环。
实际上大多数程序将 for 语句用于遍历,按顺序取出字符串或列表等数据集中的元素。后面的章节会介绍具体的程序示例。
第 6 章…遍历字符串的方法
第 7 章…遍历列表的方法
第 8 章…遍历元组、字典和集合的方法
▶ 第 6 章将对遍历这一术语进行讲解。
先判断后循环
while 语句和 for 语句在循环开始时会先判断是否继续循环(在执行循环体之前),所以有时会跳过循环体的执行(4-1 节)。这就是先判断后循环。
许多编程语言支持 do~while 语句和 repeat~until 语句等,这些语句会先循环后判断(执行循环体后判断是否继续循环),但 Python 不支持这类语句。
专栏 4-3 跳过循环和使用多个 range 进行遍历
在 for 语句的循环过程中,有时仅在特定条件下不需要进行处理操作。比如这种情况——对整数 1~12 进行循环但跳过 8。
4C-2 是使用 continue 语句实现的程序。
其实上述程序并不是一种理想的实现方式。这是因为判断是否跳过循环是有成本的。如果在进行一万次循环的情况下只需要跳过一次循环,为了跳过这一次循环就需要进行一万次判断。
当然,如果 for 语句循环中的处理操作在实际运行时会确定应该跳过的数字(比如从键盘读取或通过随机数确定)或应该跳过的数字会发生变化,此时就必须使用基于 if 语句和 continue 语句的方法了。
假设事先确定了应该跳过的数字,具体程序如代码清单 4C-3 所示。
该程序使用了第 7 章讲解的列表。程序在循环开始前生成了由数字序列1~7和数字序列 9~12 拼接后形成的列表 [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12]。
随后,程序进行循环并一个一个取出数字。因此,循环体内没有进行无效的判断。
4-3 多重循环
如果在循环语句的循环体中使用循环语句,就可以进行二重循环或三重循环。这种循环称为多重循环。本节,我们会学习多重循环的相关内容。
九九乘法表
前面编写的程序都只进行了循环。其实在循环内也可以进行循环,这类循环根据嵌套的深度分为二重循环、三重循环等。当然,这些循环统称为多重循环。
代码清单 4-17 利用二重循环打印输出了九九乘法表。
程序中的橘色底纹部分打印输出了九九乘法表,该部分的流程图如图 4-9 所示。另外,该图右侧展现了变量 i 和变量 j 的变化情况。
图 4-9 二重循环的程序流程(打印输出九九乘法表)
在外层的 for 语句(行循环)中,i 的值从 1 递增到 9。该循环对应于九九乘法表的第一行 ~ 第九行,即纵向循环。
在各行执行的内层 for 语句(列循环)中,j 的值从 1 递增到 9。这是各行的横向循环。
在行循环中,变量 i 的值从 1 递增到 9,循环了 9 次。在每一次循环中,变量 j 的值从 1 递增到 9,进行了 9 次列循环。列循环结束后程序输出换行符,准备进入下一行输出。
因此,该二重循环进行了以下处理操作。
当 i 等于 1 时:j 从 1 递增到 9 的同时以占 3 位的格式输出 1 * j 并换行
当 i 等于 2 时:j 从 1 递增到 9 的同时以占 3 位的格式输出 2 * j 并换行
当 i 等于 3 时:j 从 1 递增到 9 的同时以占 3 位的格式输出 3 * j 并换行
……
当 i 等于 9 时:j 从 1 递增到 9 的同时以占 3 位的格式输出 9 * j 并换行
▶ 字符串中的 {:3d} 表示以占 3 位的格式表示十进制数(6-3 节将对此进行详细说明)。
打印输出长方形
现在我们使用二重循环来打印输出图形。代码清单 4-18 通过排列符号 * 来打印输出长方形。
虽然行数、列数和输出内容都不同,但是该程序与输出九九乘法表的程序在结构上相同。该程序的二重循环进行了如下处理操作。
当 i 等于 0 时 :j 从 0 递增到 w-1 的同时打印输出 '*' 并换行
当 i 等于 1 时 :j 从 0 递增到 w-1 的同时打印输出 '*' 并换行
当 i 等于 2 时 :j 从 0 递增到 w-1 的同时打印输出 '*' 并换行
……
当 i 等于 h-1 时:j 从 0 递增到 w-1 的同时打印输出 '*' 并换行
打印输出直角三角形
下面打印输出三角形。代码清单 4-19 通过排列符号 * 来打印输出直角在左下角的等腰直角三角形。
程序中的橘色底纹部分打印输出了直角三角形,该部分的流程图如图 4-10 所示。另外,该图右侧展现了变量 i 和变量 j 的变化情况。
现在我们来看程序在 n 的值为运行示例中的 5 时是如何运行的。
在外层的 for 语句(行循环)中,变量 i 的值从 0 递增到 n -1,即递增到 4。该循环是对应于三角形各行的纵向循环。
在各行执行的内层 for 语句(列循环)中,变量 j 的值从 0 递增到 i 的同时进行了输出。这是各行的横向循环。
图 4-10 二重循环的程序流程(打印输出直角在左下角的等腰直角三角形)
所以,该程序的二重循环进行了如下处理操作。
当 i 等于 0 时:j 从 0 递增到 0 的同时打印输出 '*' 并换行 *
当 i 等于 1 时:j 从 0 递增到 1 的同时打印输出 '*' 并换行 **
当 i 等于 2 时:j 从 0 递增到 2 的同时打印输出 '*' 并换行 ***
当 i 等于 3 时:j 从 0 递增到 3 的同时打印输出 '*' 并换行 ****
当 i 等于 4 时:j 从 0 递增到 4 的同时打印输出 '*' 并换行 *****
程序输出的三角形按从上到下的顺序为第 0 行~第 n-1 行,所以第 i 行输出了 i+1 个 ‘',最后的第 n 行输出了 n+1 个 '’。
下面我们来编写一个打印输出直角在右下角的等腰直角三角形的程序,具体如代码清单 4-20 所示。
该程序比先前的程序更加复杂,因为要在 * 之前打印输出适当数量的空格。所以,for 语句中插入了两个 for 语句。
第 1 个 for 语句:打印输出 n-i-1 个空白字符 ''
第 2 个 for 语句:打印输出 i+1 个符号 '*'
不论在哪一行输出,空白字符和符号 * 的个数总和都为 n。
在该程序中,内层的两个 for 语句中用于计数的变量,其名称都是 _(代码清单 4-15 讲解过此编码规范)。
▶ 因为变量名使用了下划线,所以能明显看出循环体中没有使用用于计数的变量值。
另外,代码清单 4-18 中用于计数的 i 和 j,以及代码清单 4-19 中用于计数的 j 都可以使用 _ 作为变量名
(chap04/list0418a.py 以及 chap04/list0419a.py)。
总结
循环语句中有 while 语句和 for 语句,它们用于重复程序流程。因为这两个语句会先判断后循环,即事先判断是否进行处理,所以循环体可能一次也没有执行。
Python 不支持先循环后判断(执行循环体后判断是否继续循环)的语句。
range 函数可以根据给定的范围生成整数的数字序列(排列式),该数字序列是一个可迭代对象。
如果 for 语句遍历的对象是 range 函数生成的排列式,程序可以进行一定次数的循环。
用于控制循环的变量称为计数变量。如果循环体不使用计数变量的值,则可以使用 _ 作为计数变量的变量名。
多重循环指在循环语句中进行循环。
在循环语句中执行 break 语句会强行终止循环。另外,循环正常结束时进行的处理一般放在 else 代码块中执行。
在循环语句运行时,如果执行了 continue 语句,循环体后续的代码就不会被执行。
数值逐次增加 1 称为递增,数值逐次减少 1 称为递减。
如果使用增量赋值运算符(+=、-=、*=、@=、/=、//=、%=、**=、>>=、<<=、&=、^=、|=),运算和赋值操作就可以合并为单一的表达式。使用增量赋值运算符有很多好处,比如只需要记述一次用于赋值的变量名、只进行一次求值操作等。
自带电池是 Python 的特性之一。
没有内置在 Python 中的功能可以使用 import 语句导入模块来实现。
使用 time.sleep(s) 调用 time 模块中的 sleep 函数,可以使程序暂停运行 s 秒。
使用 random.randint(a, b) 调用 random 模块中的 randint 函数,可以得到 a~b 之间的随机数。