多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[Toc] # 第4章 循环结构 今天小墨首先学习了第三种程序结构:循环结构,这是一种神奇的结构,通过它能完成快速完成大量重复的事情,比如一万以内数字的相加。然后学习了一种特殊的循环:死循环。最后小墨学习了随机数的生成,并编写了猜数字的小游戏,一起来看看吧。 # [插画:早上九点、风和日丽的墨馨书屋] 时间:早上9:00 天气:风和日丽 墨博士:小墨,今天我们来做一个很经典的小游戏:猜数字,就像这样: ``` 输入猜的数字:50 小了 输入猜的数字:75 小了 输入猜的数字:88 大了 输入猜的数字:82 大了 输入猜的数字:78 大了 输入猜的数字:76 小了 输入猜的数字:77 猜对了 ``` 小墨:太好了!我哥哥就是游戏工程师,今后也能让他玩玩我做的游戏啦。 墨博士:想要做出这款游戏,我们需要学习循环结构、死循环、随机数等重要的基础语法,并且和前面的分支结构、关系运算符等内容相结合。 小墨:我准备好了。 ## 4.1 为什么需要循环 墨博士:好,小墨,如果现在让你输出5遍HelloWorld,你会怎么做? 小墨:太简单了,先写一行输出,然后复制粘贴4行出来,如下: ``` print('Hello World !') print('Hello World !') print('Hello World !') print('Hello World !') print('Hello World !') ``` 墨博士:那如果输出10遍、100遍、9527遍呢? 小墨:…… 墨博士:计算机擅长帮助人们处理重复的事情,这在python等编程语言中就是使用循环结构。 下面我们来学习两种循环结构:while循环和for循环。 ## 4.2 while循环 墨博士:小墨你知道while在英语中是什么意思? 小墨:for a while,一会儿的意思。 墨博士:while还有一个意思是当……的时候,类似于when,在Python中while取的就是这个意思。它的结构如下: ``` while 条件: 语句 ``` 程序运行流程是: 先执行第1行,判断条件是否满足 如果条件满足,则执行后面的语句 然后再次判断条件,看是否满足 如果仍然满足,则继续执行后面的语句 然后再次判断条件,看是否满足 如果仍然满足,则继续执行后面的语句 ……(不停的运行) 然后再次判断条件,看是否满足 如果仍然满足,则继续执行后面的语句 然后再次判断条件,看是否满足 如果条件不再满足了,则不再继续执行后面的语句 整个while结束。 也就是说,上述语句会一直执行,直到while后面的条件不再满足为止。这个过程就称为**循环**。这里的语句,称为**循环体**。 小墨:这个条件什么时候会不满足呢? 墨博士:问的好!while循环后跟的语句,通常不会是一句,而是多句(多个语句一起称为语句块)。其中一般就会有一句代码来控制判断条件的变化。 我们以输出10次HelloWorld的例来看: ``` n = 10 while n > 0: print('Hello World !') n = n - 1 ``` 第1行定义一个变量n,并赋值为10。 第2行中while后跟的“n > 0”是一个判断条件,判断n是不是比0大,“while n > 0”连在一起就表示当n大于0的时候,就会一直执行后面跟的代码块,也就是第3、4行内容。 第3行输出“Hello World !” 第4行是很有意思的一行,前面我们说过,“=”号是赋值运算符,它把后面的值赋给前面的变量。本句的意思是说n-1的值重新赋值给变量n。比如n为10,则10-1=9,然后把9赋值给n,此时n就变为9了。 这一句就是控制循环条件的关键一句。 整个程序的运行流程是: ``` 先执行第1行 然后执行第2行,此时判断n是不是大于0,因为此时n的值是10,10大于0,条件满足。 第一轮循环开始: 然后执行第3行,输出“Hello World !”。 然后是第4行,n是10,n = n -1之后n变为9。 此时第一轮循环结束 接着再次执行第2行,判断n是否大于0,因为n此时等于9,所以大于0,条件满足 开始第二轮循环 执行第3行,输出第3行输出“Hello World !” 然后执行第4行,n是9,n = n -1之后n变为8。 此时第二轮循环结束 接着再次执行第2行,判断n是否大于0,因为n此时等于8,所以大于0,条件满足 开始第三轮循环 执行第3行,输出第3行输出“Hello World !” 然后执行第4行,n是8,n = n -1之后n变为7。 此时第三轮循环结束 接着是第四、五、六、七、八、九轮循环 n的值分别变为了6、5、4、3、2、1 接着再次执行第2行,判断n是否大于0,因为n此时等于1,所以大于0,条件满足 开始第十轮循环 执行第3行,输出第3行输出“Hello World !” 然后执行第4行,n是1,n = n -1之后n变为0。 接着再次执行第2行,判断n是否大于0,因为n此时等于0,0不再大于0,条件不再满足,整个循环结束。 ``` 一共循环了十轮,也即第3、4行一共运行了10次,所以输出了10次的“Hello World !”。 小墨:哇啊,厉害!果然比写10遍print输出厉害太多了!这样我想输出100遍HelloWorld只需要把10改成100就可以了。 墨博士:这里的n被称为**循环变量**,你可以打印一下n的值,更能直观的看到程序的运行过程: ``` n = 10 while n > 0: print(n) n = n - 1 ``` 输出结果为: ``` 10 9 8 7 6 5 4 3 2 1 ``` 小墨:这个每次看的都是变化前的n的值,我觉得打印下变化后的n值更直观一些。可以把第3行和第4行换一下: ``` n = 10 while n > 0: n = n - 1 print('n的值为:'+str(n)) ``` 输出结果为: ``` n的值为:0 ``` 咦!怎么就输出了一个0? 墨博士:呵呵,这个正是我想告诉你的。在使用while循环的时候,需要注意后面跟的语句的缩进问题。有同样缩进的才被当成是一个语句块。这个和if后面跟的语句块的缩进是一个道理,要把它们放到while的覆盖范围中。 小墨:哦我懂了,我的第4行代码忘了添加4个空格作为缩进了。改进如下: ``` n = 10 while n > 0: n = n - 1 print('n的值为:'+str(n)) ``` 运行输出结果为: ``` n的值为:9 n的值为:8 n的值为:7 n的值为:6 n的值为:5 n的值为:4 n的值为:3 n的值为:2 n的值为:1 n的值为:0 ``` 墨博士:嗯,while循环使用简单,可读性强,用处还是很多的,为了巩固你的理解,一起来做个练习吧: > 计算1到100的数字相加之和 # [插画:数学老师说:计算1-100相加之和,高斯说:1+100=101=2+99=3+98·······,结果是5050,小墨说:使用循环就可以了] 小墨:这不是数学家高斯小时候做的那道题嘛,1+100=101=2+99=3+98·······,最后就相当于101乘以50,结果是5050。 墨博士:嗯,如果使用Python来计算,思路要回到普通的1+2+3+4+……上来。你想一下怎么做。 小墨:普通的1+2+3的思路,嗯……可以把上面的程序改一改,让n的初始值是100,然后利用while循环,让它循环个100次,然后每次都让循环变量减去1。 在循环**外**定义一个变量,用于将所有的n的值都加起来。 ``` # 定义循环变量并初始化为100 n = 100 # 定义相加的结果变量,用于接收所有n相加的结果 sum = 0 while n > 0: # 将每次循环的n都加起来 sum = sum + n n = n - 1 print('计算结果为:'+str(sum)) ``` 墨博士:嗯,不错嘛。这里还有一个小技巧,你看sum = sum + n这句,是将sum的值和n的值相加后再次赋值给sum本身,它有个简单的写法,是sum += n,就相当于sum = sum + n。这里的+=也是个赋值运算符,我们可以称它为累加赋值运算符,表示累加上某些东西之后再赋值(=)。另外需要注意这个+=是一个运算符(不是两个),使用的时候中间不能加空格。 > 墨博士提醒;除了+=,还有-=、*=、/=、%=等,表示减等、乘等、除等、余等。Python中的完整运算符及用法请参考附录B。 小墨:好的我记住了。 ## 4.3 for 循环 墨博士:接下来我们再来说另一种循环:for循环。它的完整结构为: ``` for x in m: 语句 ``` 其中x是一个变量,m需要是一个list类型或tuple类型的数据,这个我们后面单独再说,你可以简单理解为是一堆数据,x就从这一堆数据中逐个取值,如果能取到值,则执行语句,然后取下个值,直到m中的值全被取完了,则循环结束。比如 ``` for x in [1, 2, 3, 4, 5]: print(x) ``` x会从[1, 2, 3, 4, 5]中依次取出值,然后执行后面缩进的print语句。 输出结果为: ``` 1 2 3 4 5 ``` 小墨:这个似乎比while更简洁一些,但是可读性差一些。 墨博士:实际使用时根据情况选择用哪种循环就行。来做个练习吧: > 使用for循环,计算1到10的相加之和。 小墨:结合这上面的while循环中的累加的案例,可以这样写 ``` # 定义变量用于接收累加的结果 sum = 0 for x in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: # 累加 sum += x print(sum) ``` 墨博士:不错。不过问题也来了,如果想要计算1到100的相加之和呢,难道要从1写到100吗?太麻烦了!这时候我们可以使用range(n)。 range(n)是一个函数(函数也称为方法)。一个函数就是一个功能,Python提供了很多函数供我们使用,方便我们编写代码。如果把编程比作盖房子,那么函数就是已经做好的门啊窗啊钢筋啊之类的,我们可以直接拿来盖自己的房子,而不需要自己去森林里伐木做门做窗、去矿山上挖矿炼钢。 # [插画:森林里伐木、矿山上挖矿] range(n)中的n是你可以指定的数,这个函数的功能是用于生成0到n-1的整数序列,比如range(5),就可以得到0 1 2 3 4这五个数。 ``` for x in range(5): print(x) ``` 输出 ``` 0 1 2 3 4 ``` 和使用for x in [0, 1, 2, 3, 4]效果是一样的。 接下来,就交给你了小墨,编写下使用range函数配合for循环计算0到100(包括100)相加的程序吧。 小墨:好的,我试试: ``` sum = 0 # 因为要包括100,这里使用range(101)生成0-100的数,for循环依次取出这些数 for x in range(101): # 累加 sum += x print(sum) ``` 墨博士:嗯,range还有个用法就是传入两个数range(m, n),可以得到从m到n-1间所有的数,比如range(60,81)就会得到60到80间的所有数,包括60,包括80,但是不包括81。 小墨:所以计算60-80(含)间数字相加的结果的程序可以这样: ``` sum = 0 for x in range(60, 81): # 累加 sum += x print(sum) ``` 墨博士:是的。除了range()函数外,其实我们也已经学了其他的函数了。比如str()用于将整数转为字符串、int()用于将字符串转为整数、甚至print()用于将内容输出到屏幕上、input()用于接收用户的输入等都是函数。你发现什么共同点了吗? 小墨:共同点……,他们后面都跟着个小括号? 墨博士:是的!所有的函数后面都跟着有小括号,小括号中会根据需要要求我们传入相应的内容。这个我们会在后面的函数章节详细的讲解。 关于循环的使用我们就先说这么多了。 小墨:博士,我听墨哥哥曾经说过死循环,那是什么? 墨博士:墨哥哥当时怎么说的? 小墨:那天墨哥哥手机欠费停机,用网上银行充值,然后需要手机验证码,他就嘟囔了那么一句。 # [插画:手机欠费,请充值] 墨博士:…… ## 4.4 死循环 ### 4.4.1 什么是死循环 墨博士:如果一个循环的循环条件一直被满足,或者说循环体没有结束循环的可能,那么循环体就会一直执行,这种情况称为死循环,也称为无限循环。 小墨:墨哥哥那个就是结束不了了。 墨博士:是的。Python中的死循环一般用while循环来写,写法如下: ``` while True: print("Hello") ``` 因为在Python中,非0都可以用于表示True,0则表示False,所以上面的死循环也可以写成: ``` while 1: print("Hello") ``` 小墨:我来试试。编写代码,F5运行,哇好厉害!IDLE中一直在不停的打印Hello,这个打印要是丰富多彩一些,就有点黑客电影的意思啦。 # [插画补充:黑客电影电脑屏幕] ### 4.4.2 死循环的结束 小墨:诶!不对呀博士,这个我要想结束怎么办? 墨博士:死循环就是那种没法自己结束的循环,只能我们手动去结束它。在IDLE中想结束死循环使用快捷键Ctrl + C即可,效果如下: ![](https://img.kancloud.cn/b6/a1/b6a1fd0918134ecb44b61e21bd2db229_812x525.png) 或者直接关闭IDLE,会提示你是否要结束程序,选择确定就把程序结束掉了。 小墨:终于关掉了!这个死循环还挺吓人。它一般用来干什么呢? 墨博士:后面我们做的很多程序中你都能看到它的身影,另外,死循环还可以与break和continue相结合使用,来做成不定次数的循环。 ## 4.5 break 墨博士:break是打破、中断的意思,在Python中可以用于结束循环 ``` n = 5 while n >= 0: if n == 2: break print(n) n = n - 1 ``` 输出结果为: ``` 5 4 3 ``` 当n为2时,进入if分支,break结束了整个循环,开始执行后面的代码,后面没有代码则整个程序就结束了。 ## 4.6 continue 墨博士:continue是继续的意思,在Python中也用于结束循环,但是区别于break,continue是结束本轮循环并开始下轮循环,break是结束整个循环。比如: ``` for x in range(5): if x == 2: continue print(x) ``` 输出结果为: ``` 0 1 3 4 ``` 当x等于2的时候,进入if x == 2的分支中,执行continue这句,表示本次循环就此结束,不再执行print(x)这句。然后循环继续,x取出range(5)中的3,打印,依次类推。 小墨,这些你都记住了吗? 小墨:记住了。break用于结束整个循环,continue用于结束本轮循环但不结束整个循环。 ## 4.7 小墨的猜数字游戏 墨博士:好了,接下来就来完成猜数字游戏,规则如下: > 给定一个100以内的数字,然后让用户输入数字去猜,程序判断用户输入的数字是猜大了、小了还是对了,如果大了或小了,则继续猜,如果猜对了则结束程序。 小墨,接下来就看你的啦。 小墨:我先来分析一下:整个过程不知道会猜多少次,所以我没法给固定的猜的次数,应该使用一个死循环让用户能一直猜。而如果猜对了,则使用break结束循环从而结束程序,如果猜错了,就结束本轮循环,让他继续猜,是这样的吧博士。 墨博士:没错,继续说吧。 小墨:我的程序是这样的 ``` n = 65 while True: ni = int(input('输入猜的数字:')) if ni > n: print('大了') continue elif ni < n: print('小了') continue else: print('猜对了') break ``` 博士,不准看我的代码,我已经运行起来了,你来猜一猜吧。 博士:好,我来猜一下: ``` 输入猜的数字:50 小了 输入猜的数字:75 大了 输入猜的数字:63 小了 输入猜的数字:69 大了 输入猜的数字:66 大了 输入猜的数字:65 猜对了 ``` 小墨:你怎么猜这么快? 墨博士:其实我还可以更快,因为我看到你代码中的n=65了。 小墨:…… 墨博士:哈哈,你看这个游戏,如果事先已经知道了要猜的数字,就毫无可玩性了。如果我们的程序每次运行能自己生成一个随机的数字,连程序的编写者都不知道会是什么的一个数字就好了。 小墨:这样就不能作弊了。那该如何实现呢? 墨博士:这个用random模块来解决。 ## 4.8 random 墨博士:在python中,一个.py文件就是一个模块,可以看作一堆功能的整体。random模块用来生成随机数。这是Python官方给我们提供的,方便我们编写代码。 小墨:官方还真是周到啊,不光提供给了我们很多函数,还提供给了我们很多模块。 墨博士:是的。函数包含在模块中,一个模块由很多的函数(和其他的东西)组成,一个函数是一个功能,所以说它是一堆功能的整体。 小墨,你来新建一个Python文件,输入以下代码: ``` import random print(random.randint(0, 1)) ``` 注意保存的时候不要把自己新建的这个Python文件起名叫random,会和官方提供的random模块冲突。 **多次**运行,看看程序会输出什么? 小墨:有时候输出0,有时候输出1,这就是随机吧。 墨博士:嗯第1句import random用于将random模块引入进来,为什么需要引入呢?我用你的课桌来说一下。你看现在你课桌上只有笔记本、水杯和你的仙人球,为什么你不把书包、文具盒、雨伞之类的全放你课桌上,而是把这些东西放在了旁边的架子上呢? # [插画:小墨的书桌,书桌上有电脑、水杯和仙人球,书桌旁边有饮水机等] 小墨:都放课桌上也放不下呀,即使放的下也乱七八糟的。 墨博士:Python中对于函数的设计也是这样的,它把最常用的放在你手边,你直接就可以用,比如print()函数,str()函数等,而把不常用的放在了另外的模块中搁在了其他的地方,如果你想使用,需要先使用import把模块引入进来,就像你想拿文具盒中的铅笔时才会把文具盒拿过来一样。 小墨:哦我懂了,常用的放手边直接就能用,不常用的放一边先拿过来再用。 墨博士:是这个意思。再来看第2行,print后面括号中的内容是random.randint(0, 1),前面的random就是我们引入的模块,想使用模块中的函数,需要使用模块后跟点.,点后面的randint就是函数了。 小墨:这个函数和range一样,可以写两个数进去呢。 墨博士:是的,random.randint(a,b)函数会**随机**得到数字 n ,n 为 a 到 b 之间的数字(a <= n <= b),包含 a 和 b本身。这里我们传入0,1就表示,就随机得到0或者1了。 小墨:哦,我明白了,我使用这个random模块把我的程序给改造改造。 墨博士:注意把import那句放到最前面,先引进来,再使用,就像先把文具盒拿过来,再取出其中的铅笔用一个道理。 小墨:知道啦。代码如下: ``` import random n = random.randint(0, 100) while True: ni = int(input('输入猜的数字:')) if ni > n: print('大了') continue elif ni < n: print('小了') continue else: print('猜对了') break ``` 改好了博士,这次你再来猜一猜吧。 博士:好,我来猜一猜: ``` 输入猜的数字:50 小了 输入猜的数字:75 小了 输入猜的数字:88 大了 输入猜的数字:82 大了 输入猜的数字:78 大了 输入猜的数字:76 小了 输入猜的数字:77 猜对了 ``` 小墨:猜的还是挺快的嘛!我要再研究研究,做出一款更好玩的猜数字游戏出来。 ## 4.9 本章小结 墨博士总结:关于循环结构到这里就结束了。 在本章中,你首先学习了两种循环结构的用法,并使用循环完成了100内数字的累加。程序如下: ``` sum = 0 for x in range(60, 81): sum += x print(sum) ``` 这个程序运行结果没问题,但还是有两个地方需要我们注意: 一个就是这个sum,在某些IDE下可能会报警告,这是因为Python中有个自带的sum,他们重名了。所以最好改一下名字,比如叫my_sum 第二个问题是关于变量的,变量需要先初始化才能使用,比如 ``` my_sum print(my_sum) ``` 运行就会报错: ``` NameError: name 'my_sum' is not defined ``` 所以这么这里给sum指定了个0,这个称为变量的初始化。 除了两种循环结构,你还学习了循环条件永远被满足时的特殊循环:死循环,以及break和continue在循环语句中的使用。最后我们一起做了个猜数字的游戏,这个游戏中除了用到了我们学习到的分支结构和循环结构,还用到了random模块去生成随机数,这是很多程序,尤其是游戏中经常会用到的一点。