6.6 循环
程序在一般情况下是按顺序执行的。编程语言提供了各种控制结构,允许更复杂的执行路径。循环语句允许我们多次执行一个语句或语句组。图6-6所示为大多数编程语言中循环语句的执行流程。
我们已经知道条件为真(或假)时程序如何执行了。若想让程序重复执行,该怎么办呢?比如输出1~100所有数字,是写100个输出语句吗?显然你不想这样做。接下来我们学习如何解决这个问题。
图6-6 循环语句执行流程
6.6.1 while循环
我们先看如何使用简单的程序输出1~100所有数字,程序如下(文件命名while_use.py):
#! /usr/bin/python3 # -*- coding:UTF-8 -*-
n=1 while n<=100: print(f'当前数字是:{n}') n += 1
由输入程序看到,只需短短几行就可以实现这个功能,我们看输出结果(由于全部输出会太长,也没有必要,因此此处显示几行输出结果作为展示):
当前数字是: 1 当前数字是: 2 当前数字是: 3 当前数字是: 4 当前数字是: 5 ……
由输出结果看到,按顺序输出了对应结果。
该示例中使用了while关键字。在Python编程中,while语句用于循环执行程序,以处理需要重复处理的任务。基本语法形式为:
while判断条件:
执行语句……
执行语句可以是单个语句或语句块。判断条件可以是任何表达式,所有非零、非空(null)的值都为真(true)。当判断条件为假(false)时,循环结束。
while循环的执行流程如图6-7所示。
图6-7 while循环的执行流程
该流程图的意思为:首先对while条件判定,当条件为true时,执行条件语句块,执行完语句块再判定while条件,若仍然为true,则继续执行语句块,直到条件为false时结束循环。
6.6.2 for循环
我们在6.6.1小节讲述了while循环,可以看到while语句非常灵活,例如(exp_while.py):
#! /usr/bin/python3 # -*- coding:UTF-8 -*-
n=0 fields=['a','b','c'] while n<len(fields): print(f'当前字母是:{fields[n]}') n += 1
该代码实现的功能是将列表中的元素分别输出。该程序的实现没有什么问题,我们是否有更好的方式实现这个功能呢?答案是有,例如(for_use.py):
#! /usr/bin/python3 # -*- coding:UTF-8 -*-
fields=['a','b','c'] for f in fields: print(f'当前字母是:{f}')
可以看到,代码比前面使用while循环时更简洁,代码量也更少。程序执行的输出结果如下:
当前字母是: a 当前字母是: b 当前字母是: c
该示例使用了for关键字。在Python中,for关键字叫作for循环,for循环可以遍历任何序列的项目,如一个列表或字符串。
for循环的语法格式如下:
for iterating_var in sequence:
statements(s)
sequence是任意序列,iterating_var是序列中需要遍历的元素,statements是待执行的语句块。
for循环的执行流程如图6-8所示。
图6-8 for循环的执行流程
该流程图的意思为:首先对for条件判定,游标(后面会详细讲解这个词)指向第0个位置,即指向第一个元素,看sequence序列中是否有元素,若有,则将元素值赋给iterating_var,接着执行语句块,若语句块中需要获取元素值,则使用iterating_var的值,执行完语句块后,将序列的游标往后挪一个位置,再判定该位置是否有元素,若仍然有元素,则继续执行语句块,然后序列的游标再往后挪一个位置,直到下一个位置没有元素时结束循环。
我们再看以下示例(exp_for.py):
#! /usr/bin/python3 # -*- coding:UTF-8 -*-
print('-----for循环字符串-----------') for letter in 'good': #for循环字符串 print (f'当前字母 :{letter}')
print('-----for循环数字序列-----------') number=[1,2,3] for num in number: #for循环数字序列 print(f'当前数字:{num}')
print('-----for循环字典-----------') tups={'name':'小智','number':'1002'} for tup in tups: #for循环字典 print(f'{tup}:{tups[tup]}')
输出结果如下:
-----for循环字符串----------- 当前字母 : g 当前字母 : o 当前字母 : o 当前字母 : d -----for循环数字序列----------- 当前数字: 1 当前数字: 2 当前数字: 3 -----for循环字典----------- number:1002 name:小智
由上面的输入代码和输出结果可以看到,for循环的使用还是比较方便的。
提 示
如果能使用for循环,就尽量不要使用while循环。
6.6.3 循环遍历字典元素
在6.6.2小节的示例中我们已经提供了使用for循环遍历字典的代码,代码如下(for_in.py):
tups={'name':'小智','number':'1002'} for tup in tups: #for循环字典 print(f'{ tup }:{ tups[tup]}')
可以看到,此处用for循环对字典的处理看起来有一些繁杂,是否可以使用更直观的方式处理字典呢?
还记得我们前面学习的序列解包吗?for循环的一大好处是可以在循环中使用序列解包,例如(for_items.py):
tups={'name':'小智','number':'1002'} for key,value in tups.items(): print(f'{key}:{value}')
输出结果如下:
number:1002 name:小智
由输入代码和输出结果看到,可以使用items方法将键-值对作为元组返回。
提 示
字典中的元素是没有顺序的。也就是说,迭代时字典中的键和值都能保证被处理,但是处理顺序不确定。这也是用for循环输出字典中的元素时不按照顺序输出的原因。
6.6.4 迭代工具
在Python中,迭代序列或其他可迭代对象时,有一些函数非常有用。下面我们介绍一些有用的函数。
1. 并行迭代
程序可以同时迭代两个序列,输入如下(iterative_use.py):
#! /usr/bin/python3 #-*- coding:UTF-8 -*-
student=['xiaomeng','xiaozhi','xiaoqiang'] number=[1001,1002,1003] for i in range(len(student)): print(f'{student[i]}的学号是:{number[i]}')
程序执行结果如下:
xiaomeng 的学号是:1001 xiaozhi 的学号是:1002 xiaoqiang 的学号是:1003
在程序中,i是循环索引的标准变量名。
在Python中,内建的zip函数用来进行并行迭代,可以把两个序列合并在一起,返回一个元组的列表,例如(zip_func_use.py):
#! /usr/bin/python3 #-*- coding:UTF-8 -*-
student=['xiaomeng','xiaozhi','xiaoqiang'] number=[1001,1002,1003] for name,num in zip(student,number): print(f'{name}的学号是:{num}')
程序执行结果和前面一样。
zip函数可以作用于任意数量的序列,并且可以应付不等长的序列,当短序列“用完”时就会停止,例如(zip_exp.py):
#! /usr/bin/python3 #-*- coding:UTF-8 -*-
for num1,num2 in zip(range(3),range(100)): print(f'zip键值对为:{num1}{num2}')
程序执行结果如下:
zip键值对为: 0 0 zip键值对为: 1 1 zip键值对为: 2 2
由输出结果看到,zip函数以短序列为准,当短序列遍历结束时,for循环就会遍历结束。
提 示
此处用到的range函数是Python 3中的函数,在Python 2版本中存在与这个函数功能类似的xrange函数。
2. 翻转和排序迭代
我们在列表中学习过reverse和sort方法,此处介绍两个类似的函数——reversed和sorted函数。这两个函数可作用于任何序列或可迭代对象,但不是原地修改对象,而是返回翻转或排序后的版本。在交互模式下输入:
>>> sorted([5,3,7,1]) [1, 3, 5, 7] >>> sorted('hello,world!') ['!', ',', 'd', 'e', 'h', 'l', 'l', 'l', 'o', 'o', 'r', 'w'] >>> list(reversed('hello,world!')) ['!', 'd', 'l', 'r', 'o', 'w', ',', 'o', 'l', 'l', 'e', 'h'] >>> ''.join(reversed('hello,world!')) '!dlrow,olleh'
由输出结果我们看到,sorted函数返回的是一个列表,reversed函数返回的是一个可迭代对象。它们的具体含义不用过多关注,在for循环和join方法中使用不会有任何问题。如果要对这两个函数使用索引、分片及调用list方法,就可以使用list类型转换返回对象。
6.6.5 跳出循环
我们在前面的示例中讲过,循环会一直执行,直到条件为假或序列元素用完时才会结束。若我们想提前中断循环,比如循环的结果已经是我们想要的了,不想让循环继续执行而占用资源,有什么方法可以实现呢?
Python提供了break、continue等语句可用于这种情形。
1. break
break语句用来终止循环语句,即使循环条件中没有False条件或序列还没有遍历完,也会停止执行循环语句。
break语句用在while和for循环中。
如果使用嵌套循环,break语句就会停止执行最深层的循环,并开始执行下一行代码。
break语句语法如下:
break
break语句的执行流程如图6-9所示。
图6-9 break执行流程
当遇到break语句时,无论执行什么条件,都跳出这个循环,例如(break_use.py):
#! /usr/bin/python3 #-*- coding:UTF-8 -*-
for letter in 'hello': #示例1 if letter == 'l': break print (f'当前字母为:{letter}')
num = 10 #示例2 while num > 0: print (f'输出数字为:{num}') num -= 1 if num == 8: break
输出结果如下:
当前字母为: h 当前字母为: e 输出数字为: 10 输出数字为: 9
由输出结果看到,在示例1中,输出语句输出循环遍历到的字符,当遇到指定字符时,跳出for循环。在示例2中,使用while做条件判定,在语句块中输出满足条件的数字,当数字等于8时,跳出while循环,不再继续遍历。
2. continue
continue语句用来告诉Python跳过当前循环的剩余语句,然后继续进行下一轮循环。
continue语句用在while和for循环中。
continue语句的语法格式如下:
continue
continue语句的执行流程如图6-10所示。
当执行过程中遇到continue语句时,无论执行条件是真还是假,都跳过这次循环,进入下一次循环,例如(continue_use.py):
图6-10 continue执行流程
#! /usr/bin/python3 #-*- coding:UTF-8 -*-
for letter in 'hello': # 示例1 if letter == 'l': continue print(f'当前字母 :{letter}')
num = 3 # 示例2 while num > 0: num -= 1 if num == 2: continue print (f'当前变量值 :{num}')
输出结果如下:
当前字母 : h 当前字母 : e 当前字母 : o 当前变量值 : 1 当前变量值 : 0
由输出结果看到,相比于break语句,使用continue语句只是跳过一次循环,不会跳出整个循环。
6.6.6 循环中的else子句
在开发过程中,可能需要在while、for等循环不满足条件时做一些工作。该怎么实现呢?下面进行介绍。
1. 在while循环中使用else语句
在while条件语句为false时,执行else的语句块,例如(while_else_use.py):
#! /usr/bin/python3 #-*- coding:UTF-8 -*-
num = 0 while num < 3: print (f"{num} 小于 3") num += 1 else: print (f"{num} 大于或等于 3") print("结束循环!")
执行结果如下:
0 小于 3 1 小于 3 2 小于 3 3 大于或等于 3 结束循环!
由输出结果看到,while循环结束后执行了else语句中的语句块,输出“3大于或等于3”语句。
2. 在for循环中使用else语句
在for条件语句为false或结束后没有被break中断时,执行else的语句块,例如(for_else_use.py):
#! /usr/bin/python3 #-*- coding:UTF-8 -*-
names = ['xiaomeng', 'xiaozhi'] for name in names: if name == "xiao": print(f"名称:{name}") break print(f"循环名称列表 {name}") else: print("没有循环数据!") print("结束循环!")
程序执行结果如下:
循环名称列表 xiaomeng 循环名称列表 xiaozhi 没有循环数据! 结束循环!
由输出条件看到,for循环结束后执行了else语句块中的内容。