基础篇2 流程控制基础

| # Python02流程控制基础 | 06判断语句分清泾渭,关系运算明断忽微 http://www.ukoedu.com/course?course=python01&chapter=06
陈富贵
| | —- |


Attachment本节要点与难点

  1. 标准库中的os模块里提供了system()函数,可以执行操作系统命令。比如在windows中,系统命令 “ start D:\a.txt ” 就是启动程序自动打开D盘根目录中的 a.txt 文件。所以在Python程序中执行 os.system(‘start D:/a.txt’) 就可以自动打开记事本显示该文件。
    Attachment
  2. Windows系统使用反斜线 “\” 分隔文件夹和子文件夹,而 Mac OS 和 Linux 等系统中则使用普通斜线 “/” 作为路径分隔符。由于反斜线在Python中还有“转义字符”(详见后面章节)的作用,所以建议在 os.system 函数中统一使用普通斜线 “/” 。
  3. 判断结构又称“分支结构”或“分枝结构”,可以根据实际情况选择执行某一段代码。Python中的判断结构是 if 语句,其基本结构为: if 判断条件 : 若干行代码 else : 若干行代码
  4. if语句的每一个分支都可以有多行代码。这些代码必须相对于if或else关键字缩进一层。同时if与else所在的行尾必须有一个半角冒号,代表分支的开始。
  5. Python语言依靠冒号与缩进来表示“从属关系”,即一条语句从属于哪一个结构(比如if的一个分支)。所以如果两个相邻语句的缩进距离不同,就意味着二者之间存在从属关系。搞错缩进会导致严重的语法或逻辑错误,请初学者一定小心。
    Attachment
  6. 虽然Python允许使用空格或TAB作为缩进,但强烈建议只使用空格,因为TAB在不同环境下可能被翻译为不同距离,导致程序解释混乱。
  7. 可以使用一个或任意多个空格作为一层缩进,只要保证同一层次语句的缩进距离相同即可。
  8. 大于、小于等称为“关系运算符”或“比较运算符”,在Python中包括 > 、< 、>= 、<= 、== 、 != 。此外在Python2中还可以使用 <> 代表不等于
  9. 请特别注意 赋值运算符 “=” 与 关系运算符 “==” 之间的区别!很多时候程序出错就是因为把类似 “ if x==3: ” 的语句误写为 “ if x=3: ” 。

参考阅读:缩进导致的错误
如本节课所述,Python语言中的缩进非常重要,稍有差池就会导致程序无法正确解读和执行。为避免或尽快发现这种错误,请同学们牢记以下几点:

  • 只使用空格控制缩进。如果害怕自己不小心使用TAB键,可以在专业的Python编辑器(比如本课程所用的IDLE,以及功能更强大的pycharm、vscode等)中进行设置,使其自动把TAB键翻译为若干个空格。比如最新的IDLE中,TAB已经被可以自动转换为若干个空格(具体数量可在IDLE的“Options”——“Configure IDLE”菜单中设置),也可以随时运行“Format”菜单中的“Untabify Region”命令,将代码中存在的Tab都替换为若干空格。
    - 只要遇到“IndentationError: ”类错误,比如“IndentationError: unindent does not match any outer indentation level”,就马上想到是缩进出错。如果发现该行缩进正确,那么很可能就是这一行或者前面某行混用了Tab键,需要逐行排查。

下面这个博文吐槽了Python缩进带来的错误及对策,有兴趣的同学可以一读:
博客园:Python坑爹 之 代码缩进

练习1:方程计算器升级
在上节课编写的“一元二次方程计算器”中,即使用户输入了“无解方程”(比如 x^2 + x + 1 = 0),程序也仍然强行求解,报出虚数结果。
请升级该程序,使之能够先判断方程是否有解。如果发现方程无实数解,则提示“该方程无实数解”;否则与之前一样正常计算并给出结果。
判断方程是否有解的方法,是看 b^2 - 4ac 是否大于等于 0。是则有解,否则无解。
思路提示
显然,本题相当于在上节课实现的功能上增加了一层新的功能——判断。如果判断条件成立(有解),则完全执行上节课编写的计算代码;否则执行一个新的print语句,提示无解。
因此,只要编写一个 if else 结构,以 b^2 - 4ac >=0 为条件;然后把上节课编写的计算代码作为其第一个分支,再编写一个提示无解的print函数作为else分支即可。
特别注意:a、b、c三个变量的赋值仍然要放在 if 之前!否则如果不知道这三个变量的值,就无法计算 if 条件是否成立。此外,不要忘记冒号与缩进!

练习2:判断奇偶数
请编写一个判断奇偶数的程序,运行后由用户输入一个整数(比如2008),然后自动输出类似 “2008是偶数” 的信息。数字0被视作偶数。
如果运行通过,那么请继续思考:怎样编写程序,能够不使用else、只使用一个if语句,就可以实现同样的功能?(参考答案中有演示)。
思路提示

  • 可以使用模运算(%)判断奇偶数。也就是求取一个数字除以2的余数,如果为0则是偶数,1则为奇数。
  • 注意if语句的缩进和冒号。
  • 对于“不使用else”的挑战,可以用下面的思路实现:
  1. 首先用一个变量保存最终输出的文字信息(也就是print中的内容)
  2. 在进入if结构前,先把这个变量赋值为“奇数”或“偶数”,也就是假定一个“默认结果”
  3. 然后判断这个数字是否与默认情况不同(“偶数”或“奇数”),如果是则修改变量,将其重新赋值为正确结果
  4. 最后,无论判断结果为何,均用print语句将该结果变量打印出来

| # Python02流程控制基础 | 07层层判断层层递进,种种运算种种关联 http://www.ukoedu.com/course?course=python01&chapter=07
陈富贵
| | —- |

Attachment
本节要点与难点

  1. 当判断结构需要使用多个分支时,可以在if与else两个分支之间使用任意多个elif子句,代表“否则如果”。elif子句的格式要求与if子句完全一样,都要有判断条件和冒号。
  2. 同一个if结构中的if、elif和elseif必须对齐,因为它们之间不存在相互从属关系。一个if结构中,必须有且只有一个if子句;可以有零或一个else子句;可以有零或任意多个elif子句。如果有else子句,则必须是最后一个分支。
    Attachment
  3. 在使用多分支时,必须注意各子句判断条件之间的包含关系,否则会导致逻辑错误。
  4. 使用嵌套判断结构可以实现“层层递进审核”的需求。套在里面的if结构其实与同层次其他语句没有任何区别,只要注意缩进关系即可。
  5. 如同视频中8分20秒演示的,同一个需求可以用多种嵌套思路实现。只有先理清业务逻辑,才能做出最精简也最正确的代码。
    Attachment
  6. 一个判断子句中可以使用多个关系表达式表达复杂条件,只要使用逻辑运算符 And、Or、Not 等将其组合在一起即可,但是其中每个子条件都必须书写完整。
    Attachment
  7. 对于“ a>5 and a<8 ”形式的条件,可以简写为:“ 5 < a < 8 ”
  8. Not的优先级 > And的优先级 > Or的优先级 。可以使用圆括号修改优先级。
    Attachment

练习1:判断闰年
请编写一个判断闰年或平年的程序,运行后由用户输入一个整数(比如2008),然后自动输出类似 “2008是闰年” 的信息。
闰年的判断方法为:如果一个数字可以被4整除,同时不能被100整除,那么这一年就是闰年。但是,如果这个数字可以被400整除,那么它仍然是闰年。
请分别使用 elif 、嵌套if 以及 单条if语句结合逻辑运算 等三种方式实现本作业。
运行时请先使用以下几个年份测试程序是否正确:
1996年是闰年1998年是平年2000年是闰年2100年是平年
思路提示

  • 本例与前一节的“判断奇偶数”本质相同,只不过增加了判断分支和层次。
  • 同样可以使用模运算判断一个数字能否被4等数字整除。
  • 注意if语句的缩进和冒号、各个分支的先后顺序与包含关系,以及逻辑运算的优先级。
  • 如果使用 elif 模式(不使用缩进和逻辑运算),那么应该注意个分支的包含关系,确保前面分支的条件不包含后面分支的条件。具体来说,先判断是否被400整除,如果不能再判断是否被100整除,最后判断是否被4整除。

练习2:方程虚数解
在上节课编写的“升级版方程计算器”中,如果用户输入了“无解方程”(比如 x^2 + x + 1 = 0),则提示“无实数解”并拒绝计算。不过事实上,即使 b^2-4ac 小于 0 ,python也能自动按照虚数运算法则计算出结果(例如 “ 2 + 0.8j ”,其中 “j” 就是高中数学里表示虚数的 “i” )。
所以请再次升级该程序,使之按以下规则运行:

  1. 先判断方程是否有解。如果发现方程有实数解,则正常计算并给出结果。
  2. 如果在 1 中判断结果为无实数解,则提示“此方程无实数解,是否需要虚数解?(Y/N):”,并接收用户输入。
  3. 如果用户输入为 “Y” 或 “y”,则仍然执行计算并给出结果(算式与实数解时完全相同);否则显示 “方程无实数解”。
    思路提示仔细分析题目要求,可以发现本题相当于在上节课实现的else分支(无实数解)中增加了一层新的判断——是否要虚数解。所以应在此分支中再嵌套一个判断语句。
    不过这个新的判断语句需要判断的是:用户是否输入过“Y”或“y”。因此在它之前应该先写一个input语句,请用户输入字母。同时应该把这个input的结果保存到一个变量中(假设为k),以便记住该输入字母并在后面的判断语句中分析。
    此外,既然用户输入 “Y” 和 “y” 都合法,那么在if语句中应该考虑使用逻辑运算符“or”。

| # Python02流程控制基础 | 08While之道周而复始,进退有约合则循环 http://www.ukoedu.com/course?course=python01&chapter=08
陈富贵
| | —- |

Attachment
本节要点与难点Attachment

  1. 循环结构可以将指定的若干行代码重复执行,直到符合某个条件为止。Python中典型的循环结构为 “ while 循环条件 : ” ,格式要求及条件写法与 if 语句完全相同。
  2. 从 while 后面的冒号开始,下面相对while存在缩进的连续代码均属于“循环体”,将会被重复执行。而从第一个不相对while缩进的语句开始,后面的代码都不再属于这个while的循环体;对于这些语句,只有当while循环彻底结束后才会被执行到。Attachment
  3. 如果在 while 的循环条件中使用了变量,那么该变量必须在此之前就已经赋值,否则第一次执行循环就会出错。
  4. while 循环在每执行一次循环体后,都会重新检查循环条件。如果循环条件仍然成立则再次执行循环体,否则结束循环。因此假如循环体中的代码不可能改变循环条件的判断结果,那么该循环将永远执行下去,成为“死循环”。Attachment
  5. 死循环可以用于设计“监听”等机制,但大多数情况下应当被避免。假如不小心出现死循环,可以在Python交互窗口或系统命令窗口中按下 “Ctrl” + “C” 强制程序中断;或者可以在Windows任务管理器中强制关闭Python进程。
  6. 循环中最常用的两个模式就是“计数器”与“累加器”。计数器是在进入循环前先定义一个值为0的变量,然后每次循环均让该变量增加1,这样循环结束时该变量的值就是循环次数。累加器与之类似,只不过每次循环时让该变量增加某个统计指标的样本数值,这样当循环结束时,该变量的数值就是所有样本的该指标汇总。使用计数器和累加器时,要特别注意变量第一次赋值的位置和数值!基础篇2 流程控制基础 - 图13
  7. 如果在循环条件中判断计数器的当前数值,就可以实现“指定次数的循环”。不过更方便的方法是使用《基础篇》第11回将要介绍的 for 循环。
    参考阅读:关于死循环本节课杨老师特别强调了“注意避免死循环”的问题。在python中,while 是最容易发生死循环的结构,只要我们稍不注意、忘记在循环体内提供一个能够退出循环的操作,它就会永远持续下去。
    不过正如课程中所言,有时候我们也会故意设计一个死循环以实现“无限监听”的目的,比如下一节课中随机生成音乐旋律的例子。对于这种有意设计的死循环,我们一般称为“无限循环”,以摘除 “死循环” 一词中蕴含的 “不小心玩死” 的含义。
    根据造成死循环的原因,我们可以把它分为不同类型。比如下面的 “逻辑错误型”死循环,按照其执行逻辑,i 永远不可能变成大于5的数字:
    i = 1 while i<5: i=1 i=i+1
    此外还有一种 “奥尔德森型” 死循环,一般用来代表在设计图形操作界面(GUI)等用户交互模块时,虽然设计了退出循环的条件,但是由于程序还在调试等原因,忘记给用户提供这种操作,从而导致死循环。比如在我们熟悉的语音电话系统中,假如听到这样的提示 “ 按1重听,按10退出 ” ,那么我们就可以说该系统出现了一个“奥尔德森循环”,因为电话上根本就没有“10”这个按键,我们即使尝试按下“1”、“0”,也会被当做“1” 而进入重听循环。
    之所以把这种错误成为“奥尔德森循环”,是因为一个发生在微软公司内部的故事:奥尔德森(Alderson)是当年Access开发团队中的一名程序员。在他负责开发的一个模块中有一个弹出窗口,只要按下 “OK” 或 “Cancel” 按钮,该窗口就会退出消失。程序都写得很好,只不过在调试时才发现,这位仁兄忘记了在该窗口里面放入 “OK” 和 “Cancel” 按钮,所以用户一调出这个窗口,就只能面对杯具了……
    练习1:重复录入 请修改上一节编写的“判断闰年”程序,使之能够循环运行:程序启动后用户可以反复多次输入年份,并获知其是否为闰年。只有当用户输入“END”时,程序才结束退出。
    思路提示本例与视频课程中的“重复录入”例子思路完全相同,可参照编写。不过题目中的条件 “输入’END’即结束” 可能需要动些脑筋:
    如果写成 year = int ( input (‘请输入一个年份:’)) ,那么当用户输入“END”后就会出错,因为“END”无法用int函数转换成数字。
    不过以目前大家所掌握的知识也可以解决该问题,方法就是先用 year = input(‘请输入一个年份’) 得到用户输入,无论它是数字还是文本。然后首先判断其是否为“END”,是则停止循环,否则用 year = int ( year ) ,将其转换为整数。
    在 year = int ( year ) 这句代码中,程序首先执行等号右边,将year(比如字符串“1990”)交给int函数,最终得到一个数字1990。然后再将这个数字赋值给year变量,从而使year的内容从字符串变为真正的整数。这个过程与 i=i+1 是完全一样的。
    练习2:简化复利计算请修改第五回中编写的“复利计算”程序:用户不仅输入本金与利率,而且还要输入一个“最大借款年数”。程序将会输出从第一年到最大借款年之间每年度的千克总额。效果如下:
    请输入本金:100请输入年利率:0.2请输入最大借款年数:5第 1 年欠款总额为 120第 2 年欠款总额为 144第 3 年欠款总额为 172第 4 年欠款总额为 207第 5 年欠款总额为 248
    思路提示
  8. 整体思路:使用计数器实现一个指定次数的循环。该计数器变量从1开始,每次循环增加1,只要小于等于用户输入的最大年数就持续循环。
  9. 循环体里只需一行代码,也就是找出上一版程序中反复书写四次的代码,将其中唯一变化的细节用计数器变量(也就是第几年)代替即可。
  10. 不要忘记在循环体中给循环变量(计数器)增加1,否则将会变成死循环!

| # Python02流程控制基础 | 09随机数千般可能难预料,break一言不合就退群 http://www.ukoedu.com/course?course=python01&chapter=09
陈富贵
| | —- |


Attachment本节要点与难点

  1. 要善于利用循环变量。将重复出现但有规律的代码用循环变量代替,才能写出风格精简、易于维护的程序。
  2. 当Python程序通过os.system等机制调用外部软件时,Python程序本身并不会自动停下等待,而是在发出指令后继续运行自身。使用标准模块time中的sleep()函数,可以让Python程序暂停若干秒。
  3. 两个字符串可以用加号“+”连接在一起构成一个新的字符串。通过将固定的字符串常量(比如“成绩是”)与字符串变量(比如score)相加,就可以灵活构造出“成绩是123”这样形式的文本。这种“字符串构造”技巧在实际工作中十分常用。
  4. 加号两边不能一个是数字、另一个是字符串。如果需要做字符串连接操作,应当先用str函数根据数字得到对应字符串;如果需要做算术加法操作,则要先用int、float等函数得到字符串对应的数字。
  5. 标准模块random中提供了各种生成随机数的函数,其中randint(a,b)可以生成一个[a,b]区间的整数。
  6. 可以利用 while 1==1: 这种形式构造一个死循环,然后在循环体中判断,一旦符合某个条件就执行 break 语句,从而中断并跳出循环。构造死循环更正规的方式是 while True 。
  7. break语句可以跳出当前循环,continue语句则是直接进入下一次循环、跳过循环体后面的剩余代码。尽管二者用起来十方便,但如果滥用则会让程序代码难以阅读、不易理清其执行流程。所以在正规开发中应尽量避免使用。基础篇2 流程控制基础 - 图15 基础篇2 流程控制基础 - 图16
    参考阅读:随机数发生器就像我们在视频课程里说的,“随机数”不仅在编写电子游戏中,而且在编写各类程序时都十分常用,比如“年会抽奖”、“交通流量模拟”、“考试题库自动组卷”等等。很多同学都会对“随机数是怎样产生的”这个问题很好奇,而且也很想知道“随机数真的是不可预测的么”,甚至“有没有可能预测抽奖程序产生的下一个随机数字,从而提前买好彩票……”。
    其实大多数计算机程序中提供的随机数函数(也就是随机数生成器),严格的说都属于“伪随机数发生器”。它们大多是通过类似高斯函数的数学模型计算出来的。这些数学模型(函数)的特点是:即使让自变量按照 1、2、3、4 这样极其规律的顺序变化,所得到的结果数字也会波动极大,完全看不出互相之间有什么规律。因此在程序中每次调用随机数函数时,系统都会自动向这些函数(数学模型)里输入一个数字(比如当前系统时间)作为自变量,然后将其返回的结果作为随机数返回给我们。这种作为自变量的数字则成为用于生成随机数的“种子”。所以理论上讲,这种“伪随机数”是可以预测的,但是至少需要具备高超的数学专业知识以及强大的运算能力,而且还要有机会接触到运行随机数程序的软硬件系统以便获取算法、种子等必要信息,所以可以说几乎无法实现。
    除此之外,也有更加专业的系统舍弃数学模型,转而采用硬件甚至环境中的某些特征作为随机数,比如探测系统内部或周围的热力学噪声变化等等。显然,这样生成的随机数要比数学模型更加难以预测。
    由于随机数的实际应用非常广泛,所以本课程在《提高篇》中还会涉及到这部分内容,届时将会有更加深入的讲解。
    练习1:语音抽奖请模仿本视频课程中“随机播放音乐”的案例,编写一个“自动抽奖并宣读中奖号码”的程序。具体方案为:
  8. 先用windows或苹果系统等自带的“录音机”程序(win7系统在“开始菜单”——“附件”中,win10系统在“开始菜单”的程序列表中可以找到),或手机等其他设备,亲自录下10个音频文件,内容就是“零”到“九”十个数字的读音。将这些音频文件保存在硬盘指定位置,并用数字作为文件名,比如 “3.m4a”。
  9. 编写程序,使之能够随机生成5个0到9之间的数字。每生成一个数字,就播放与之对应的那个音频文件,从而实现连续读出五位中奖号码的功能。
  10. 调试通过后,建议按照自己的兴趣增加一些“花样”,比如每次公布号码前都播放一段音乐,或者加上 “第一位号码为:” 等说明信息。
    思路提示本例与视频课程中的 “随机播放音乐” 基本相同,只不过循环次数固定为5次。所以关键思路如下:
  11. 指定一个用作“计数器”的变量比如 i,并为其赋初始值 0 。
  12. 制作一个while循环,循环条件为 i<5 。循环体内不要忘记让 i 每次增加1,以免死循环。
  13. 循环体内调用 randint 函数,生成一个0到9之间的数字。
  14. 利用这个数字构造出对应的音频文件名(假设音频文件名就是数字名如“3.m4a”)。
  15. 使用 os.system 播放该音频,并使用 time.sleep 让本程序等待若干秒。
    特别提示:在构造文件名字符串时,请不要忘记用str函数,根据随机数字生成对应的字符串!否则直接用数字与字符串连接将会出错。

| # Python02流程控制基础 | 10调试加注释 降低出错率,循环套循环 突破小周天 http://www.ukoedu.com/course?course=python01&chapter=10
陈富贵
| | —- |

Attachment
本节要点与难点

  1. 循环结构经常被用来实现“穷举法”,即将所有可能选项依次试验一遍,直到找出正确答案。
  2. 如果程序中出现了“机械重复、规则明确”的代码段,那么就应考虑将这些重复代码段抽象为一个循环(或者后面会讲到的函数、类等等)。
  3. 对于一个双重循环,假如外层循环有m圈、内层循环有n圈,则总循环次数是 m × n 。
  4. 在多重循环中,一个break语句只能跳出它所在的那一层循环,并不会一次跳出所有循环。
  5. 程序错误(Bug)包括三种:
  • 语法错误:因不符合语法而无法执行,Python解释器会自动发现该错误并报告。
  • 逻辑错误:符合语法可以执行,但是由于计算过程(算法)不正确,最终无法得到正确的结果。
  • 运行错误:符合语法可以执行,但是在运行中遇到异常(比如 x = 2 / a ,但是 a 在某一时刻变为0),导致程序被迫中断。
  1. Python程序第一行的行首不能有任何空格、缩进,否则会因缩进问题导致语法错误。
  2. 各种现代开发环境都提供了集成调试工具。在IDLE中可以按照以下步骤启动调试器:
  3. 进入Python Shell命令行窗口(在代码编辑器菜单选“Run”——“PythonShell”)
  4. 在命令行窗口菜单中选“Debug”——“Debugger”,弹出Debug Control窗口
  5. 在Debug Control窗口中选中“Source”复选框
  6. 在Debug Control窗口中按下“Step”按钮
    Attachment
  7. Debug Control 窗口中各个按钮含义如下:
  • Go按钮:直接运行代码,直到遇到断点或程序结束为止
  • Step按钮:单步执行,即只执行一步程序(代码窗口中的灰色高亮条即所执行语句)
  • Over按钮:假如当前执行的代码要调用某个函数,那么点击Step会进入该函数的代码,而Over则不会进入该函数,直接取得其结果
  • Out按钮:假如当前执行语句位于某个被调用函数(比如print)的内部,则按下Over后会将该函数全部执行完并返回到调用方
  1. 在单步执行过程中,可以随时在 Debug Control 窗口的最下面看到各个变量的当前数值,从而分析出问题所在。
  2. 可以在代码编辑器上右键点击某行代码,选择“set breakpoint”在此行设置断点。程序中可以设置多个断点,右键“clear breakpoint”可以清除所有断点。
  3. 保持良好的代码风格,对于预防错误、提高易读性非常重要。可以通过以下两个方式改进代码风格: 使用空行对代码合理分组。使用 # ,在关键代码前书写一行注释语句。如果需要连续书写多行注释,也可以使用三个引号 ‘’’ 。
  4. 在调试程序时如果需要临时删除某一行代码,可以将其标记为注释语句以便随时恢复。
  5. 程序设计的基础就是三大流程结构,包括 “顺序结构”、“分支(判断)结构” 和 “循环结构” 。
    参考阅读:“Bug”的来历关于Bug和Debug这两个术语的来历,计算机界流传着很多不同版本的故事。其中比较为公众普遍认可的说法(引自维基百科),是哈佛大学女科学家Grace Hopper于1946或1947年工作时发现一台Mark II计算机出现错误,经过她与同事的排查,最终发现故障原因是一只飞蛾卡在了中继器上。由于Bug(虫子)一词早在1870年代就已经被爱迪生等人用于指代“技术错误”,所以Hopper等人也从这只飞蛾开始,将计算机错误称为Bug。
    Attachment
    Hopper发现的史上第一个计算机Bug (即那只被钉在错误日志上的飞蛾)
    其实,“调试错误”(Debugging)一词也是在计算机之前就被航空业用于指代“错误排查”,所以在Hopper提出“Bug”的称谓后,计算机界很快也开始使用Debug一词代表“错误调试”。

作业1:水仙花数 求解“水仙花数”是一道非常经典的循环练习题。如果一个三位数( 100 —— 999 )等于它每一位数字的立方和,则称这个数为“水仙花数”。比如 153 = 1^3 + 5^3 + 3^3,所以 153 就是一个水仙花数。
本题的正确输出结果应当包括四个数字: 153 370 371 407
以我们目前(《基础篇》第十回)已经讲解过的知识,同学们至少可以通过两种方式编写出解题程序。这里建议大家使用三重循环穷举法回答本作业,思路及答案可以见本页标签。
除了嵌套循环外,大家也完全可以只使用一层循环即找出所有水仙花数。强烈建议大家在完成嵌套循环解法后,再尝试思考这种解法。我们会在本章发布一周之后,在本页 “解题思路” 中增加这一解法的提示。
思路提示本例与视频课程中的 “穷举法解数学题” 基本相同,只不过循环次数增加到3次,运算条件也有变化。关键点如下:

  1. 所有三位数都可以用 a100 + b10 + c 表示,而它们每一位的立方和都是 a3 + b3 + c**3 。
  2. 所以只要做一个三层循环,最外围将a从1循环到9,第二层将b从0循环到9,第三层将c从0循环到9,就可以穷举出所有三位数。
  3. 在第三层循环里面,把穷举到的三位数abc按照(1)中的表示方法进行比较,即可判断出它是否为水仙花数。如果是,将abc打印出来即可。
    特别提示:要格外注意a、b和c的初始化位置。比如,如果把b=0写在所有循环之前,程序就无法找到全部答案。具体原因与视频课程中调试器示例相同。

作业2:多次抽奖上节课(第九回)的作业是编写一个“自动抽奖并宣读中奖号码”的程序。本节请在此基础上进行扩充,改为连续宣读三个中奖号码。具体效果参考如下:

  1. 仍然使用上节课录制的音频文件读数字。此外再录制三个人声音频,“一等奖是”、“二等奖是” 和 “三等奖是” 。这三个音频文件(假设为wav格式)可以命名为“bonus1.wav”、“bonus2.wav”和“bonus3.wav”,以便于程序调用。
  2. 编写程序,使之能够循环三次。第一次先播放“一等奖是”,然后随机生成五位中奖号码并播出;第二次先播放“二等奖是”,然后再随机生成中奖号码并播出,如此类推。
  3. 调试通过后,建议按照自己的兴趣增加一些“花样”。
    思路提示本例只需在上一节课的核心代码外面,再“套上”一层循环即可。外面这层循环应使用一个计数器以保证循环三次,同时每次循环均可以根据计数器的数值(即第几次循环)找到指定的“X等奖”音频并播放。在播放“X等奖”音频时,可以使用 ‘bonus’ + i + ‘.wav’ 这种形式得到 bonus3.wav 形式的文件名。
    Attachment