在上一篇《手把手陪您学Python》17——循环的终止中,我们学习了break和continue两种循环终止的方法,同时利用循环的终止方法,对我们的游戏程序进行了优化。
今天,我们将要学习的是另外一种循环语句——for循环。for循环重要到什么程度呢?就这么说吧,可能没有一个程序不需要用到for循环的。所以,大家加把劲,把for循环学好,我们的技能就能再上一个台阶了。
先来了解一下for循环的作用和几个概念。
for循环用于“遍历”一个集合(字符串、列表、元组)或迭代器。
之所以把“遍历”加上了双引号,是因为这个词太常用了,以至于我都认为“遍历”这个词就是给for循环定制的。从含义上看,遍历可以理解为逐个读取。从对象上看,遍历的对象是一个集合或者迭代器,同时,也只有集合或迭代器才能够被“遍历”。
集合的类型可以是字符串、列表或者元组。字符串前面已经讲过了,遍历字符串就是逐个读取字符串中的每一个字符。列表虽然我们还没有讲,但前面已经接触过了,就是像[1, 2, 3, 4, 5]这样被中括号括起来的几个元素的集合。遍历列表就是逐个读取列表中的每一个元素。元组也是我们后面要讲的概念,它是形如(1, 2, 3, 4, 5)这样被小括号括起来的几个元素的集合(先不需要知道元组的概念)。遍历元组就是逐个读取元组中的每一个元素。
迭代器的概念稍微有点复杂,大家简单了解一下就行。迭代是访问集合元素的一种方式,迭代器是一个可以记住遍历位置的对象(Python是一切皆为对象)。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束,只能往前不会后退。所以,遍历的过程就是迭代,遍历的对象就是迭代器。
了解完概念,我们再来看看for循环的结构。for循环是由for...else...组成的,其中else部分也可以省略。
for 元素 in 集合:
执行语句1
else:
执行语句2
与while循环不一样的是将while循环的判断条件改为了for循环的迭代过程。while循环是根据判断条件决定循环的次数,而for循环是根据集合中的元素个数决定循环的次数。
与while循环一样的是格式的要求(冒号以及缩进),else可以省略(for循环常用的也是省略else的结构),以及也可以使用break和continue终止循环,且终止的规则相同(break终止整个循环,continue终止当次循环)。
for循环的语句结构翻译成自然语言,可以表达为:
对集合中的每一个元素,执行语句1,遍历完集合后,执行语句2。
从自然语言的角度看,for循环的过程比较好理解,难的可能就是集合和遍历的概念。接下来,我们就根据for循环中集合的不同类型,给大家演示几个实例,让大家直观感受一下遍历的过程,以及不同类型集合的遍历效果。
字符串是我们目前最为了解的类型了,所以我们就从字符串开始。
1、字符串
字符串是由一个个字符组成的,所以字符串的元素就是这一个个字符。当我们将字符串作为for循环的集合进行遍历的时候,就是从左到右逐个读取字符串的每一个字符。
在刚刚介绍for循环结构的时候,其实还有一个关键点是没讲的。这就是在for循环的迭代语句“for 元素 in 集合”中,“元素”并不真的是集合中的元素,而是为了让大家理解这个遍历的过程,而写成了“for 元素 in 集合”的样子。
事实上,“for 元素 in 集合”中,元素的位置是一个变量名。在每一次的迭代过程中,这个变量名被循环赋值成集合中的每一个元素的值。当集合是字符串时,这个变量就会被赋值成字符串中的每一个字符;当集合是列表或者元组时,这个变量就会被赋值成列表或者元组中的每一个元素。
下面,先以字符串为例,一起看一下这个遍历的过程、赋值的过程和循环的过程。
In [1]: str = "Hello World!" # 集合是字符串,每一个字母、空格、标点符合都是一个字符,或者说是一个元素
for letter in str: # letter是一个变量名,可以起任何的变量名,只是为了程序好阅读,才根据元素的内容,起名叫做letter
print(letter) # 每一次循环,变量letter就会被赋值成一个字符(元素)的值,并执行print()
Out[1]: H
e
l
l
o
W
o
r
l
d
!
在上面的实例中,集合是"Hello World!"(不包括"")。遍历的过程是逐个读取集合中的每一个字符(元素)的值,即:H、e、l、l、o、 、W、o、r、l、d、!。之后再在每一次循环中,将这些值逐个赋值给变量letter,最后执行print。
这个实例比较简单,但也非常直接,大家应该可以稍微理解这个遍历并赋值的过程了。还没有理解也没关系,我们后面还有很多实例,帮助大家理解。
下面这个是稍微难一点的实例,一是在字符串中增加了转义字符,让我们来看看是如何遍历的,二是增加了continue和break两个循环终止的条件,三是增加了else,让我们看看是否会起作用。
In [2]: str = "\\Hello World!\n" # 转义字符不会被当做两个字符处理的,遍历时\\就是一个字符\,\n也就是一个回车符(打印出来是一行空行)
for abc in str: # 随机换了一个别的变量名,也是一样的,说明变量名和遍历的元素是没有关系的,不是因为变量名是letter,才按照字母遍历的
print("该次遍历打印的字符是:{},".format(abc), end='')
if abc == 'o' or abc == 'r':
print("即将执行continue,不会打印下面那句话,循环继续。")
continue
if abc == 'd':
print("即将执行break,不会打印下面那句话和else,循环终止。")
break
print("会打印这句话,循环继续。")
else: # else因为也是循环结构内的一部分,会被break终止,不会运行
print("打印完成")
Out[2]: 该次遍历打印的字符是:\,会打印这句话,循环继续。
该次遍历打印的字符是:H,会打印这句话,循环继续。
该次遍历打印的字符是:e,会打印这句话,循环继续。
该次遍历打印的字符是:l,会打印这句话,循环继续。
该次遍历打印的字符是:l,会打印这句话,循环继续。
该次遍历打印的字符是:o,即将执行continue,不会打印下面那句话,循环继续。
该次遍历打印的字符是:,会打印这句话,循环继续。
该次遍历打印的字符是:W,会打印这句话,循环继续。
该次遍历打印的字符是:o,即将执行continue,不会打印下面那句话,循环继续。
该次遍历打印的字符是:r,即将执行continue,不会打印下面那句话,循环继续。
该次遍历打印的字符是:l,会打印这句话,循环继续。
该次遍历打印的字符是:d,即将执行break,不会打印下面那句话和else,循环终止。
上面的实例虽然有些复杂,但其实是可以被看做两部分。一部分是循环的遍历过程,和第一个实例没有太大差别,只不过增加了一个转义字符的情况。第二部分是循环语句的终止,和我们在上一篇举的例子差不多。
了解完字符串作为集合是如何遍历的,我们再来看看列表。
2、列表
列表我们虽然没有学过,但是之前的一些实例中已经用到了。列表就是被中括号括起来的一个有序元素组,现在大家把列表理解为一个容器就可以。其中被逗号分隔的就是一个个元素,元素可以是数字、字符串、变量等很多类型。
举个简单的例子,让我们看看列表作为集合是如何遍历的。因为之前已经演示过循环的终止以及else的实例了,后面为了更聚焦于遍历的过程,就不再编写复杂的实例了。
In [3]: a = 'Python'
lst = [1, 'a', 2, 'b', a, '3'] # 第5个元素a是个变量,第6个元素'3'是字符串不是数字
for a in lst: # 变量名虽然是可以随便起的,但建议在程序中,还是使用有意义的变量名
print(a)
Out[3]: 1
a
2
b
Python
3
在上面的实例中,一共出现了5次“a”,但每一个“a”的含义或者作用都不尽相同。
第1个'a'是一个变量名,它的值是一个字符串'Python',这是一个赋值过程;
第2个'a'就是一个字符串;
第3个'a'和第1个'a'都是指的同一个变量,这里是引用变量a的值;
第4个'a'也是一个变量名,给他赋值的是集合中的各个元素。此时虽然第1个'a'的赋值结果失效了,但不会影响列表中的元素值,因为在运行第2行程序后,lst的值已经变成了[1, 'a', 2, 'b', 'Python', '3'];
第5个'a'和第4个'a'指的是同一个变量,也是引用变量a的值。
3、元组
元组也是我们后面要讲的一种数据结构,在这里不想太多涉及。它的形式是用小括号括起来的一个有序元素组。所以,对于上面将列表做为集合的内容,对元组是完全一样的,只要把中括号变成小括号就可以了。
讲到这里,集合的各种类型就讲完了,但还有一种在for循环中最常用的遍历方法需要介绍。之所以叫做“方法”而不叫作“类型”,是因为这种方法的实质就是列表,只是使用了一个可以很方便生成列表的函数作为表达式,这个函数就是range()。
4、range()函数
之前,我们为了说明for循环遍历的过程,举的例子都是将元素显示出来的,而且元素的类型也是尽量的多样化,以扩展大家的思维。但实际上,我们在应用for循环时,最常用的还是遍历数字序列。比如下面的图形,就是应用for循环,通过遍历数字序列实现的。
In [4]: for num in [1, 2, 3, 4, 5, 6, 7, 8, 9]:
print(' ' * (9 - num), '* ' * num, ' ' * (9 - num), sep='')
Out[4]: *
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
这里的数字序列使用的是列表,但还是将每一个元素都显示出来了。元素个数比较少的时候还好,如果数字很大,或者数字变化规律比较复杂时,这样就不是很方便了。这时,我们就需要range()函数出场了。
range()函数的作用就是生成整数数字序列的列表,其基本的语法表达式为:
range(start_num, end_num, step)
由于Python使用的是左闭右开的规则,因此start_num是数字序列的起始数字(写几就是几);step是步长,即数字序列中每一个数字间的间隔值;end_num是数字序列最后一个数字不会超过或者等于的值,但最后一个数字具体是多少,需要通过star_num和step计算而来。
strat_num的默认值是0,step的默认值是1。因此,当只写range(end_num)时,默认生成的就是0到end_num-1的数字序列。例如,range(10)就相当于[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。
当省略step,只写range(strat_num, end_num)时,就是生成从strat_num到end_num-1的整数序列。例如,range(-5, 10)就相当于[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。
当所有的参数都被设定时,将会从start_num开始,按照step的增量(step为负数时为负增量)产生序列,直到end_num,但最后一个数字,既不能等于end_num也不能超过end_num。例如,range(-5, 10, 3)就相当于[-5, -2, 1, 4, 7](右开区间,不能包括10)。
当step参数为正数时,start_num要小于end_num,上面就是这种情况的例子。
当step参数为负数时,start_num要大于end_num。例如,range(10, -5, -3)就相当于[10, 7, 4, 1, -2](同样不能包括-5)。
如果step为正数,但是start_num小于end_num,或者step为负数,但是start_num大于end_num,虽然程序不会报错,但该数字序列遍历的结果为空,就会结束遍历,转而执行else(如果有的话)或者for循环之后的语句。
In [5]: for num in range(10, -5, 3):
print(num)
print("程序结束。")
Out[5]: 程序结束。
所以,range()函数在for循环中的作用,是为了让我们更方便地产生一个整数列表作为遍历的对象,与列表作为集合进行遍历的情况一样,并没有其它太多的概念上的内容需要介绍。
利用range()函数,之前打印图形的程序就可以简化为:
In [6]: for num in range(10):
print(' ' * (9 - num), '* ' * num, ' ' * (9 - num), sep='')
Out[6]: *
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
以上就是对for循环的介绍。至此,我们就将Python的控制流语句if、while、for,循环终止的方法break和continue全部介绍完了。如果大家能够把这几篇文章的内容吃透,那么至少在判断、循环、终止等语句控制方面,大家和高手是不存在什么知识储备方面的差别了,剩下的就是大家在程序中如何灵活地运用了。
下一篇,我们将对之前学习的内容进行一个小小的总结,同时会编写一个较为复杂的游戏程序,其中不仅应用到了if、while、for循环及其嵌套,还包括的了循环的终止、随机函数、字符串函数等知识点,希望有助于大家对之前内容的消化、理解和应用,敬请关注。
感谢阅读本文!如有任何问题,欢迎留言,一起交流讨论^_^
欢迎扫描下方二维码,关注“亦说Python”公众号,阅读《手把手陪您学Python》系列文章的其他篇目,或点击下方链接直达。
《手把手陪您学Python》3——PyCharm的安装和配置
《手把手陪您学Python》5——Jupyter Notebook
For Fans:关注“亦说Python”公众号,回复“手18”,即可免费下载本篇文章所用示例语句。