![人工智能基础教程: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=1738849417-OeV7TFXAwU14jWxuFX1n812mF8zhSDGs-0-cef5d5fb6b3939d940be4e39b8a90a54)
图3.5 循环语句流程图
循环语句允许执行一条语句或语句组多次,允许更复杂的执行路径。下面来学习本章最重要的两个语句:while循环语句和for循环语句。
3.2.2 while循环语句
具体语法:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0381.jpg?sign=1738849417-Xnh9hNFvPjV7QNmWg2vWp0fxPBh72Fpd-0-1dcac38a9d485f0af9ff7242fe862e5b)
while循环语句中的suite_to_repeat会一直循环执行,直到表达式(expression)的值为假(False)。执行流程图如图3.6所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0384.jpg?sign=1738849417-gswnmMRrGv4Sgujth7yB3z69JXUZ9VuZ-0-9b3a8df154c089516d2bc8b689705505)
图3.6 while循环语句流程图
接下来用一个日常的例子来更加明了地展示while的用法:假如老师让你完成全班同学的成绩评定(全班同学的排列是有序的),你该怎么做呢?在这种情况下,需要为全班的每一个同学都重复执行一次评定代码,也就是在循环中执行评定代码。因为已经将全班同学的排列设置为有序的,这使得我们不用考虑班级成员的姓名,直接用数字代替。具体程序如程序3.4所示。
程序3.4 全体成绩评定:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0383.jpg?sign=1738849417-clpkXdz1HxBC7HgM6jTGd9WMhtAy6gRa-0-f0427a78e8b09d07b7368631cddfad54)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0385.jpg?sign=1738849417-1eya9guPfNhL2hO2OGmSp59LXHIaqrEE-0-1beca0bda23d71d1ae66d53a73d23b0f)
分析:
程序的第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=1738849417-j9Hjg4gYjwn0oPhdgedU544s2utDRUhT-0-3930ae22bd74f789880d0a0257db6b0a)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0387.jpg?sign=1738849417-dMf4CplpAHcSovXPxlo5RejZV3rH9uYh-0-59d54e15ad133c3f06f099c576183374)
分析:
在程序3.5中,我们使用Python提供的Fraction方法来表示分数,它的原型是:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0388.jpg?sign=1738849417-8K3VEdwCrIoW57CLMTjZTLprrks0pdLQ-0-bef7e3c6ddd675edd1fb30cf40453ed8)
也就是说,它接收两个参数,第一个作为分子,第二个作为分母。它可以直接与数运算(如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=1738849417-l0z8xZ6O1FKtb05IOW8tolplVB0gl5xY-0-19c51d9f3242676bce0e6f526e7bfc25)
图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=1738849417-jcTemaMZp3hVu8h2fjviUEnB0yOgrP6M-0-1344a15aa6e44a19ae66a474c6874eee)
for循环是Python提供的另一个循环机制,它会依次访问一个已选定的可迭代对象(例如,我们很常见的字符串、序列或是元组)中的所用元素,即遍历可迭代对象,这个过程在具体语法中就是将iter_var设置为iterable中的当前元素,当iterable中的所有的条目(如序列中的项)都处理过后结束循环。执行流程如图3.8所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0391.jpg?sign=1738849417-sNyyrODQOjHLdGz1A5LuRhwsUyAONwpG-0-bca52b68d2e2188a6f9208c95ae34a63)
图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=1738849417-6ou9hAxPiYFHH68HQUoAiQ1J4FhYWf9l-0-58247720afee38a5c54f7c6e6cebc71b)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0393.jpg?sign=1738849417-0qZXj0SsuP0JUgTDkmI1kofFfZkOmO7z-0-17c13ca7da29a29823edaa8dea315744)
分析:
程序中name是一个列表,代表着小组成员名单,我们用for语句迭代这个列表,其中item变量在每次的循环中都会被赋值为列表中的某个特定的元素,以供循环中的语句使用。
介绍完使用序列项迭代之后,我们来看看另一种方法,使用序列索引迭代。不同于使用序列项迭代,使用序列索引迭代就如同字面意思所说,操作的重点在于拿到序列索引号并通过它获取序列中的项。还是上面的例子,我们改用序列索引迭代实现,具体程序如程序3.7所示。
程序3.7 使用序列索引迭代:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0394.jpg?sign=1738849417-SGTRq6fGTSQtVSxjjwsYGWtsRE4jb895-0-d62354b7def526c8b3ec1a39bf03a774)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0395.jpg?sign=1738849417-7PCKX3DGNuqBUxgw4Vc5qns5kv524sou-0-65800858278258521641cabb683f93ca)
分析:
本程序和程序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=1738849417-PaAvASIMdgbM4eVArxLwoN3Zfc4JO0ad-0-f6ad718d0e7d1243a306a638f0f98524)
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=1738849417-r15atra2aqQTeQXTc00apRve6lIF44Z7-0-d6990a2d0df38715d0ee7ffac29dc0d1)
第一种只接收一个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=1738849417-etyoD7JVYR7klKINg8p70oEzfMqFSXcS-0-19335d81ebc918c7cef0d86f41383451)
图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=1738849417-n3jnmWLpMCLsbVu4Tk95x0f0dccUvA4a-0-67d34903f6e18938a10b0d526ec22416)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0399.jpg?sign=1738849417-oFryR2pzxIYZt2AHGAd95bwUYmDL5HR1-0-b65cd3fb8c32cfc1db13f5d79ce77ab4)
分析:
本程序涉及物理课中的一个很简单的测速实验,在这里我们假设已经测量完纸带的间距并将它们存储在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=1738849417-p2RjrWTwYoqZUZ0x0DxwPITXEJxvGUHU-0-19c4dd599fab75a378410a627e4d2bd3)
图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=1738849417-mUCHYMvSMqdCQHZk2yCvX65TTVPrnLgP-0-a141167480d2367b430706f9379002dc)
图3.11 break语句流程图
现在我们已经对break语句有了一定的了解,接下来用一个例子来实践一下。我们都笔算过最大约数,接下来就用Python实现算出最大约数。
程序3.9 求一个数的最大约数:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0403.jpg?sign=1738849417-Ol75TEo2s88tM1Fj6GOIUdqpJIrAaVvb-0-755c7f7c4dbb6447ed6d7a99f6e3a9b3)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0404.jpg?sign=1738849417-Wfejq0dbBh0XJg8f4iIos0ngAsyB3Aix-0-743759d4de2b4bc1a31d24499dc152c3)
分析:
在程序3.9中,因为count的值是不断递减的,所以第一个能整除num的数便是我们要找的,后续的数就没有必要考虑了,使用break语句跳出循环。程序流程图如图3.12所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0405.jpg?sign=1738849417-sWOgu7HRoZobleRF5dLHRrW9rQxcwH11-0-b0353d649a26e1b88a31b3970391d451)
图3.12 程序流程图
3.2.5 continue语句
我们可以将continue语句理解为跳过当前的循环块,继续该循环的下一次迭代。先来看看continue语句的执行流程图,如图3.13所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0408.jpg?sign=1738849417-MhV0gGAykzOMoJ105jFxP7PLej4ZUNOn-0-39e9f8ed74614f2ff3fc0cef5298b60a)
图3.13 continue语句流程图
接下来用一个判定提交的选项是否正确(假设正确的选项为C)的程序来看看continue语句是如何工作的。
程序3.10 判断提交选项:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0406.jpg?sign=1738849417-J8iuhGcRfBnr7h8vUi4Rp0Ed8jGEciMG-0-bae62bf3082769f1ca4977031389e066)
输出:
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0407.jpg?sign=1738849417-9IeOtM6Hyt9a7IOnBFhFr0ftV6WPrSXD-0-7afb70f7c83c2fb3ed9b260a44dc1622)
分析:
在这个程序中不仅用到了continue语句,还用到了许多之前提到过的语句。在第1行中使用True作为while的循环条件以达到可以不断地对选项进行判断的目的,若输入不是C,那么将使用continue语句跳过本次循环,重复下一次循环,直到输入C并执行break语句,才终止循环并获得Congratulations!。程序流程图如图3.14所示。
![](https://epubservercos.yuewen.com/EFD799/15289821505523106/epubprivate/OEBPS/Images/aa0409.jpg?sign=1738849417-KzgU2fJPCLpVVQz0ZdNjTQhlWJbwT4V4-0-4d2b9743eff3d903fcdaa6ea163e4163)
图3.14 程序流程图