![人工智能基础教程:Python篇(青少版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/783/26846783/b_26846783.jpg)
3.2 循环控制语句
本节将详细介绍Python中的while循环语句和for循环语句以及一些控制语法。
3.2.1 理解Python中的循环语句
Python提供了while循环语句和for循环语句以及break、continue等循环控制语句,循环语句执行的一般流程如图3.5所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0382.jpg?sign=1739168536-Z7w0Juxluz3d3VmxtjoIPlb0TNKy044K-0-8bd12152fd71bf3b58b68c0f2773765c)
图3.5 循环语句流程图
循环语句允许执行一条语句或语句组多次,允许更复杂的执行路径。下面来学习本章最重要的两个语句:while循环语句和for循环语句。
3.2.2 while循环语句
具体语法:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0381.jpg?sign=1739168536-YNGkQ9k5XMiBnkqmZDxujMBRwoDha8xu-0-6f9cbf893ad33b693b25f5a90065dfc1)
while循环语句中的suite_to_repeat会一直循环执行,直到表达式(expression)的值为假(False)。执行流程图如图3.6所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0384.jpg?sign=1739168536-XmGSPqtdkQ2m95Ef05qXkvhrIMBbVchq-0-bb39019c8ba86cf162233b933f009a55)
图3.6 while循环语句流程图
接下来用一个日常的例子来更加明了地展示while的用法:假如老师让你完成全班同学的成绩评定(全班同学的排列是有序的),你该怎么做呢?在这种情况下,需要为全班的每一个同学都重复执行一次评定代码,也就是在循环中执行评定代码。因为已经将全班同学的排列设置为有序的,这使得我们不用考虑班级成员的姓名,直接用数字代替。具体程序如程序3.4所示。
程序3.4 全体成绩评定:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0383.jpg?sign=1739168536-YPVl3726SY6vc59s6cqXVlIxEkf20KL1-0-668e6b9ba35af950e5a50391cd305842)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0385.jpg?sign=1739168536-0NZeEejj06zWz1Y82FJMuk7ktTNyEhDR-0-4aec9d4cf3df4e71e79db809c2bd2f13)
分析:
程序的第5~15行是循环执行部分,从缩进格式可以看出它们是在while循环中的,注意最后一行的 count += 1,这是count = count + 1的简写。我们设定count让它在每次的循环之后加1,以此达到控制程序的目的。直到count自增到不再小于num的时候循环结束,也就是说,当count与num相等时不会进入循环结构中,因为这个特性而且我们还要保证循环的次数,所以将count的初值设为0,循环条件设置为count<num,但这样又与编号差1,所以在打印时我们使用count+1(也可以让count初值为1,循环条件为count<=num,这样在打印的时候用count即可)。
注意:
(1)在循环中使用自增变量(就是程序3.4中的变量count)控制循环条件是一种很常见的用法。
(2)对于while循环的循环控制变量要小心对待,因为有些值永远不会为False,这样的循环是永远不会结束的,当然这也不一定是坏事,这取决于实际情况。
通过上面的例子,while语句的用法已经明确了,接下来我们用一个等差数列的例子进一步讨论while的用法。这是一个简单输出指定项数的等差数列(首项为2/3,公差为2/5)各项的程序,具体的各项为2/3、16/15、22/15、28/15(这里只列举数列的前4项)。我们将在这个例子中引入Python中分数的表达方法,这样在本例之外可以使用Python做更多的事情。关于程序的具体解析在分析中有更详细的说明。具体程序如程序3.5所示。
程序3.5 输出指定项数的等差数列的各项:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0386.jpg?sign=1739168536-U9tdluntJKWtwMxYPbef5hvq5eVQmwE1-0-337bab2df45ebb4999e796479e72e117)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0387.jpg?sign=1739168536-Dv1P7crc7yqOMD4lBqDohBMo3KG2kjUv-0-7876f174b3dd1a68a2438ee20e0ee4f8)
分析:
在程序3.5中,我们使用Python提供的Fraction方法来表示分数,它的原型是:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0388.jpg?sign=1739168536-c8ClWDS0SY0ZZf19sJO7AjLgsXU9PxhY-0-0115e40b7571940351399198a22b151f)
也就是说,它接收两个参数,第一个作为分子,第二个作为分母。它可以直接与数运算(如Fraction(5,16)+3),也可以在Fraction对象之间相互运算〔如Fraction(1, 16)* Fraction(3,16)〕。另外,关于模块、对象的详细使用方法后文会介绍,在这里你可以简单地将Fraction(2, 3)理解为我们平时笔算时写的2/3。
现在继续回到程序中,第1行中的语句可以简单地理解为将Fraction模块导入到此程序中,这样就能用Fraction方法了。接下来我们使用step表示公差,在while循环中不断地加到首项上,以此构造一个等差数列,并在最后输出。while循环还是和上一个例子一样,是通过自增变量控制的。程序流程图如图3.7所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0390.jpg?sign=1739168536-4qdaUNlrsnpe1NvtS3C31rMvScryZMRj-0-ea119a25594aeae0ec5a9e318f171889)
图3.7 程序流程图
思考题:
Fibonacci数列是数学中一个非常重要的数列,它指数列前两项为1并且从第3项开始往后,每一项都等于前两项之和。例如,数列的前5项为“1, 1, 2, 3, 5”。在这里我们来思考一下,如何使用while循环语句输出最后一项小于1000的Fibonacci数列。
关于Fibonacci数列还有一种递归实现,关于递归的概念以及具体实现方式在本书的函数部分会详细讲解。
3.2.3 for循环语句
具体语法:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0389.jpg?sign=1739168536-XsqLkZEvma5E6sxNJjmiAfGJvW9haNjc-0-03406642101a2b87f2b63b127a029498)
for循环是Python提供的另一个循环机制,它会依次访问一个已选定的可迭代对象(例如,我们很常见的字符串、序列或是元组)中的所用元素,即遍历可迭代对象,这个过程在具体语法中就是将iter_var设置为iterable中的当前元素,当iterable中的所有的条目(如序列中的项)都处理过后结束循环。执行流程如图3.8所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0391.jpg?sign=1739168536-b4V3zOtnnwLKB2FY7g8UvQSAcR0ygzt6-0-67bdf3b0008a16a605ca2cc5d7be8d40)
图3.8 for循环语句流程图
注意:
读完上面这一段for循环的具体介绍,你可能会有疑问,什么是迭代?你可以将迭代理解为一种环形结构,它也叫循环,while和for语句也被称为迭代语句。
如果你之前接触过C/C++或者Java的话,请一定注意,Python中的for语句与其他编程语言的用法不同。
到这里我们已经知道了for循环会遍历一个可迭代对象,下面来看看如何使用它。我们介绍两种基本方法:使用序列项或者序列索引。假如已经拿到你们小组的名单,而老师需要你将小组成员的名字和组号一同输出。诸如此类的情况,for语句可以很好地实现。
程序3.6会使用序列项迭代来遍历输出名单上的名字。
程序3.6 使用序列项迭代:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0392.jpg?sign=1739168536-BwEzCKCBqOgP2phzxsxmQMf2a8jU9inZ-0-38fc66043c9e7af3eeecc6ecfd041b62)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0393.jpg?sign=1739168536-S2jwDpdJdyxQbARHTN0tf8dLJzijkOiU-0-b0a4b9d8a592e709df41c29d1922cb64)
分析:
程序中name是一个列表,代表着小组成员名单,我们用for语句迭代这个列表,其中item变量在每次的循环中都会被赋值为列表中的某个特定的元素,以供循环中的语句使用。
介绍完使用序列项迭代之后,我们来看看另一种方法,使用序列索引迭代。不同于使用序列项迭代,使用序列索引迭代就如同字面意思所说,操作的重点在于拿到序列索引号并通过它获取序列中的项。还是上面的例子,我们改用序列索引迭代实现,具体程序如程序3.7所示。
程序3.7 使用序列索引迭代:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0394.jpg?sign=1739168536-t4ISLfJg9UQtdBeXmVNkCM1U4bSjCZA5-0-40ae1ff7707ae9c9520c408400de00fb)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0395.jpg?sign=1739168536-zke46or2UuF3djiGobAAFBEhnK8tiFY1-0-b812c1d9ff1cd68155a3196cef43b686)
分析:
本程序和程序3.6看上去相似,但是并不相同,在本程序中你会发现一个略显生疏的函数—range,它的作用是返回一个序列,这个序列正好就是我们需要的迭代序列。我们将range的参数设置为姓名列表(name)的长度,这样从range(len(name))中获取的数即可作为name的索引数(注意使用range函数获取序列的值是从0开始,len(name)-1结束),再使用name列表的切片操作来获取与索引值相对应的项,并在for循环中完成输出。
看完分析你可能仍对range函数存有疑惑,下面我们再详细地谈谈range函数。先来看看完整的range函数:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0396.jpg?sign=1739168536-GwgFiQAdzv23jXNfmzRStcV12JsZrM9t-0-72f161d7aba54dbf2858c2b682ab40b9)
range函数会返回一个包含所有项的列表,这里我们假设项为i, i会满足start<= i < end,从start开始,i每次递增step(注意:step一定不能为0)。例如,range(2, 6, 2)会返回列表[2, 4]。
我们经常用到的是它的两种简化形式:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0397.jpg?sign=1739168536-qvZZzhfFVrybOzC5UM3iFYpSJROG15Xp-0-c9f59c30a7681d2c75129b27b1304381)
第一种只接收一个end值,它的start默认为0,step为1。例如,range(3)会返回列表[0, 1, 2]。第二种接收两个值,它的step默认为1。例如,range(2, 4)会返回列表[2, 3]。
当for循环涉及数字操作的时候,使用range函数是很有用的。
提示:
如果你的程序需要考虑到性能的问题,那么对于上文所讲的序列项迭代和索引迭代,序列项迭代的速度会更快。
注意:
这里,我们已经知道 for 循环会依次访问一个已选定的可迭代对象的所有元素。你是否会疑惑,它是怎样做到的呢?实际上,在 for 循环的内部,它会自动帮我们调用迭代器的next()方法来达到遍历的效果,它也会捕获StopIteration异常使循环结束。这样便可以完成上文所提到的功能。
现在你应该对于for循环有了更深的理解,接下来用一个大家都很熟悉的例子巩固一下。在物理课上你应该做过用打点计时器测速度的实验(人教版高中物理必修1第一章),现在假设我们拿到的纸带如图3.9所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0400.jpg?sign=1739168536-ugAQpsQO0K8dKEY84tIjMQJUhpLd7v9u-0-ac257bf07dd794e0725772ceb20c1a66)
图3.9 用于实验的纸带
已知打点计时器所用电源频率为50Hz, AB距离为0.0040m, BC距离为0.0102m, CD距离为0.0106m。我们要求每一段的平均速度。具体程序如程序3.8所示。
程序3.8 求纸带上每段距离的平均速度:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0398.jpg?sign=1739168536-GiW5wbRcq6IN9tRVzHj0jm8Cwi8VgD8a-0-25e82e49a7078315995d6f0325c30acd)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0399.jpg?sign=1739168536-cJbxUv7PTikt1Nagjaxglz7dn7CzuBAh-0-989a0e8e7fe1a36e99d73f2119846c28)
分析:
本程序涉及物理课中的一个很简单的测速实验,在这里我们假设已经测量完纸带的间距并将它们存储在item_len列表中,用item遍历获取item_len列表中的各段距离值用于for循环中的具体操作。由打点计时器所用的电源频率为50Hz可知,纸带上两点间隔的时间为0.02s,得到这些条件后,用/vxt=DD来求得每段的平均速度。程序流程图如图3.10所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0401.jpg?sign=1739168536-0fMfwgJB4wXnGyHcTiZwjiCusbEakRLS-0-3633f52d82b06a7620a95f7eba37288a)
图3.10 程序流程图
注意:
在编程的时候,我们可以让两个字符串相加达到组成一个字符串的目的,但是,在程序3.8中的print语句中你不能使用print("{0} m/s" + item/sec)的形式进行输出,因为此时item/sec是float类型,这样做会让你的程序报错:TypeError: must be str, not float。像这种从其他信息中构造字符串正是format()方法大有用武之地的地方。
3.2.4 break语句
break语句在控制中很常见,它可以终止当前的循环,即跳出循环语句执行程序中的下一条语句。执行流程图如图3.11所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0402.jpg?sign=1739168536-BtkZqASmkxD8Ru4eEjabQANoGLZOtsmX-0-b98a654f88f36593751a91a61f8abefd)
图3.11 break语句流程图
现在我们已经对break语句有了一定的了解,接下来用一个例子来实践一下。我们都笔算过最大约数,接下来就用Python实现算出最大约数。
程序3.9 求一个数的最大约数:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0403.jpg?sign=1739168536-lJhSGNpVBWgWuO0n5XUXEK4VGYvyhnei-0-d0b891bf3850b972099631b3c118933f)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0404.jpg?sign=1739168536-JdBaYcrbjGIjGSt6bt6N75p6Q9agSpKX-0-68d3e986436b387e76dfdeba54b01479)
分析:
在程序3.9中,因为count的值是不断递减的,所以第一个能整除num的数便是我们要找的,后续的数就没有必要考虑了,使用break语句跳出循环。程序流程图如图3.12所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0405.jpg?sign=1739168536-5Ai0wZH1w4F8qkRdcDtQfCiJnzbSJiGL-0-1ede80a56be3d3013a69754122e7e8aa)
图3.12 程序流程图
3.2.5 continue语句
我们可以将continue语句理解为跳过当前的循环块,继续该循环的下一次迭代。先来看看continue语句的执行流程图,如图3.13所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0408.jpg?sign=1739168536-xqYguuRsB1PBm6Y289L99XExe7GWHD8c-0-7add7128114cab28cad13c7ecb385ccc)
图3.13 continue语句流程图
接下来用一个判定提交的选项是否正确(假设正确的选项为C)的程序来看看continue语句是如何工作的。
程序3.10 判断提交选项:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0406.jpg?sign=1739168536-9RqK133TdsXBRBEWXVLOMss5uWrBRYGO-0-8a186793ea17751f9752fbd54f8d7119)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0407.jpg?sign=1739168536-RwWmB64bev3bjFo9rdXW8ibRgT7aszfH-0-1f24829056b432a17f81c41e8738c73b)
分析:
在这个程序中不仅用到了continue语句,还用到了许多之前提到过的语句。在第1行中使用True作为while的循环条件以达到可以不断地对选项进行判断的目的,若输入不是C,那么将使用continue语句跳过本次循环,重复下一次循环,直到输入C并执行break语句,才终止循环并获得Congratulations!。程序流程图如图3.14所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0409.jpg?sign=1739168536-J9pxNbfF72NjYHL54e1lGFtto7SDw7KE-0-c0b3c1ae9a92b6c616c2c21d7abe43c3)
图3.14 程序流程图