我心中的王者:Python-第7章 循环设计
假设现在笔者要求读者设计一个1加到10的程序,然后打印结果,读者可能用下列方式设计这个程序。
程序实例ch7_1.py:从1加到10,同时打印结果。
# ch7_1.py
sum = 1+2+3+4+5+6+7+8+9+10
print("总和 = ", sum)
执行结果
总和 = 55
如果现在笔者要求各位从1加到100或1000,此时,若是仍用上述方法设计程序,就显得很不现实。
另一种状况,如果一个数据库列表内含有1000名客户的名字,现在要举办晚宴,所以要打印客户姓名,如果用下列方式设计,将是很不实际的行为。
程序实例ch7_2.py:一个不完整且不切实际的程序。
# ch7_2.py -- 不完整的程序
vipNames = ['James','Linda','Peter', ... , 'Kevin']
print("客户1 = ", vipNames[0])
print("客户2 = ", vipNames[1])
print("客户3 = ", vipNames[2])
...
...
print("客户999 = ", vipNames[999])
你的程序可以要写超过1000行,当然碰上这类问题,是不可能用上述方法处理的,不过幸好Python语言提供我们解决这类问题的方式,可以轻松用循环解决,这也是本章的主题。
7-1 基本for循环
for循环可以让程序将整个对象内的元素遍历(也可以称迭代),在遍历期间,同时可以纪录或输出每次遍历的状态或称轨迹。for循环基本语法格式如下:
for var in 可迭代对象: # 可迭代对象英文是iterable object
程序代码区块
可迭代对象(iterable object)可以是列表、元组、字典与集合或range( ),在信息科学中迭代(iteration)可以解释为重复执行,上述语法可以解释为将可迭代对象的元素当作var,重复执行,直到每个元素皆被执行一次,整个循环才会停止。
设计上述程序代码时,必须要留意缩排的问题,可以参考if叙述观念。由于这里笔者介绍列表(list),所以读者可以想象这个可迭代对象(iterable)是列表(list),第8章笔者会讲解元组(Tuple),第9章会讲解字典(Dict),第10章会讲解集合(Set)。另外,上述for循环的可迭代对象也常是range( )函数产生的可迭代对象,将在7-2节说明。
7-1-1 for循环基本运作
例如,一个NBA球队有5位球员,分别是Curry、Jordan、James、Durant、Obama,现在想列出这5位球员,那么使用for循环执行这个工作就很适合。
程序实例ch7_3.py:列出球员名称。
# ch7_3.py
players = ['Curry', 'Jordan', 'James', 'Durant', 'Obama']
for player in players:
print(player)
执行结果
Curry
Jordan
James
Durant
Obama
上述程序执行的观念是,当第一次执行下列语句时:
for player in players:
player的内容是‘Curry’,然后执行print(player),所以会印出‘Curry’。由于列表players内还有其他的元素尚未执行,所以会执行第二次,当执行第二次下列语句时:
for player in players:
player的内容是‘Jordan’,然后执行print(player),所以会印出‘Jordan’。由于列表players内还有其他的元素尚未执行,所以会执行第三次,第四次,当执行第五次下列语句时:
for player in players:
player的内容是‘Obama’,然后执行print(player),所以会印出‘Obama’。第六次要执行for循环时,由于列表players内所有元素已经执行,所以这个循环就算执行结束。下列是循环的流程示意图。
7-1-2 如果程序代码区块只有一行
使用for循环时,如果程序代码区块只有一行,它的语法格式可以用下列方式表达:
for var in 可迭代对象:程序代码区块
程序实例ch7_4.py:重新设计ch7_3.py。
# ch7_4.py
players = ['Curry', 'Jordan', 'James', 'Durant', 'Obama']
for player in players:print(player)
执行结果 与ch7_3.py相同。
7-1-3 有多行的程序代码区块
如果for循环的程序代码区块有多行程序时,要留意这些语句同时需要做缩排处理。它的语法格式可以用下列方式表达:
for var in 可迭代对象:
程序代码
程序代码
……
程序实例ch7_5.py:这个程序在设计时,首先笔者将列表的元素英文名字全部改成小写,然后for循环的程序代码区块有2行,这2行(第4和5行)皆需内缩处理,player.title( )的title( )方法可以处理第一个字母以大写显示。
# ch7_5.py
players = ['curry', 'jordan', 'james', 'durant', 'obama']
for player in players:
print(player.title( ) + ", it was a great game.")
print("I can not wait to see your next game, " + player.title( ))
执行结果
Curry, it was a great game.
I can not wait to see your next game, Curry
Jordan, it was a great game.
I can not wait to see your next game, Jordan
James, it was a great game.
I can not wait to see your next game, James
Durant, it was a great game.
I can not wait to see your next game, Durant
Obama, it was a great game.
I can not wait to see your next game, Obama
7-1-4 将for循环应用在列表区间元素
Python也允许将for循环应用在6-1-2节和6-1-3节所截取的区间列表元素上。
程序实例ch7_6.py:列出列表前3位和后3位的球员名称。
# ch7_6.py
players = ['Curry', 'Jordan', 'James', 'Durant', 'Obama']
print("打印前3位球员")
for player in players[:3]:
print(player)
print("打印后3位球员")
for player in players[-3:]:
print(player)
执行结果
打印前3位球员
Curry
Jordan
James
打印后3位球员
James
Durant
Obama
这个观念其实很有用,例如,你设计一个学习网站,想要每天列出前3名学生基本数据同时表扬,可以将每个人的学习成果放在列表内,同时用降幂排序方式处理,最后可用本节观念列出前3名学生资料。
注:升幂是指由小到大排列。降幂是指由大到小排列。
7-1-5 将for循环应用在数据类别的判断
程序实例ch7_7.py:有一个files列表内含一系列文件名,请将“.py”的Python程序另外建立到py列表,然后打印。
# ch7_7.py
n = 5
number1 = list(range(n))
print("当n值是%d时的range( )列表 = " % n, number1)
n = 8
number2 = list(range(n))
print("当n值是%d时的range( )列表 = " % n, number2)
执行结果
当n值是5时的range( )列表 = [0, 1, 2, 3, 4]
当n值是8时的range( )列表 = [0, 1, 2, 3, 4, 5, 6, 7]
程序实例ch7_8.py:有一个列表names,元素内容是姓名,请将姓洪的成员建立在lastname列表内,然后打印。
# ch7_8.py
n = 5
print("当n值是%d时的range( )列表元素:" % n)
for number in range(n):
print(number)
n = 8
print("当n值是%d时的range( )列表元素:" % n)
for number in range(n):
print(number)
执行结果
当n值是5时的range( )列表元素:
0
1
2
3
4
当n值是8时的range( )列表元素:
0
1
2
3
4
5
6
7
7-1-6 删除列表内所有元素
程序实例ch7_9.py:Python没有提供删除整个列表元素的方法,不过我们可以使用for循环完成此工作。
# ch7_9.py
start = 2
end = 6
number1 = list(range(start, end))
print("当start值是%2d, end值是%2d时的range( )列表 = " % (start, end), number1)
start = -2
end = 3
number2 = list(range(start, end))
print("当start值是%2d, end值是%2d时的range( )列表 = " % (start, end), number2)
start = -5
end = -1
number3 = list(range(start, end))
print("当start值是%2d, end值是%2d时的range( )列表 = " % (start, end), number3)
执行结果
当start值是 2, end值是 6时的range( )列表 = [2, 3, 4, 5]
当start值是-2, end值是 3时的range( )列表 = [-2, -1, 0, 1, 2]
当start值是-5, end值是-1时的range( )列表 = [-5, -4, -3, -2]
7-2 range( )函数
Python可以使用range( )函数产生一个等差序列,我们又称这等差序列为可迭代对象(iterable object),也可以称是range对象。由于range( )是产生等差序列,我们可以直接使用,将此等差序列当作循环的计数器。
在前一小节我们使用”for var in 可迭代对象”当作循环,这时会使用可迭代对象元素当作循环指针,如果是要迭代对象内的元素,这是好方法,但是如果只是要执行普通的循环迭代,由于可迭代对象占用内存空间,所以这类循环需要占用较多系统资源。这时我们应该直接使用range( )对象,这类迭代只有迭代时的计数指针需要内存,所以可以节省内存空间,range( )的用法与列表的切片(slice)类似。
range(start, stop, step)
上述stop是唯一必须的值,等差序列是产生stop的前一个值。例如:如果省略start,所产生等差序列范围是从0至stop-1。step的预设是1,所以预设等差序列是递增1。如果将step设为2,等差序列是递增2。如果将step设为-1,则是产生递减的等差序列。
由range( )产生的可迭代等差对象的数据类型是range,可参考下列实例。
下列代码用来打印range( )对象内容。
上述代码执行循环迭代时,即使是执行3个循环,但是系统不用一次预留3个整数空间储存循环计数指针,而是每次循环用1个整数空间储存循环计数指针,所以可以节省系统资源。下列是range( )含step参数的应用,第1个是建立1~10的奇数序列,第2个是建立每次递减2的序列。
7-2-1 只有一个参数的range( )函数的应用
当range(n)函数搭配一个参数时:
range(n) # 它将产生0, 1, … , n-1的可迭代对象内容
下面来测试range( )方法。
程序实例ch7_10.py:输入数字,本程序会将此数字当作打印星号的数量。
# ch7_10.py
start = 2
end = 6
print("当start值是%d, end值是%d时的range( )列表元素:" % (start, end))
for number in range(start,end):
print(number)
start = -2
end = 3
print("当start值是%d, end值是%d时的range( )列表元素:" % (start, end))
for number in range(start,end):
print(number)
start = -5
end = -1
print("当start值是%d, end值是%d时的range( )列表元素:" % (start, end))
for number in range(start,end):
print(number)
执行结果
当start值是2, end值是6时的range( )列表元素:
2
3
4
5
当start值是-2, end值是3时的range( )列表元素:
-2
-1
0
1
2
当start值是-5, end值是-1时的range( )列表元素:
-5
-4
-3
-2
7-2-2 有2个参数的range( )函数
当range( )函数搭配2个参数时,它的语法格式如下:
range(start, end)) # start是起始值,end-1是终止值
上述可以产生start起始值到end-1终止值之间每次递增1的序列,start或end可以是负整数,如果终止值小于起始值则产生空序列或称空range对象,可参考下列程序实例。
下列代码是使用负值当作起始值。
程序实例ch7_11.py:输入正整数值n,这个程序会计算从0加到n之值。
# ch7_11.py
start = 2
end = 9
step = 2
number1 = list(range(start, end, step))
print("当start值是%2d, end值是%2d, step值是%2d时的range( )列表 = " % (start, end, step), number1)
start = -2
end = 9
step = 3
number2 = list(range(start, end, step))
print("当start值是%2d, end值是%2d, step值是%2d时的range( )列表 = " % (start, end, step), number2)
start = 5
end = -5
step = -3
number3 = list(range(start, end, step))
print("当start值是%2d, end值是%2d, step值是%2d时的range( )列表 = " % (start, end, step), number3)
执行结果
当start值是 2, end值是 9, step值是 2时的range( )列表 = [2, 4, 6, 8]
当start值是-2, end值是 9, step值是 3时的range( )列表 = [-2, 1, 4, 7]
当start值是 5, end值是-5, step值是-3时的range( )列表 = [5, 2, -1, -4]
7-2-3 有3个参数的range( )函数
当range( )函数搭配3个参数时,它的语法格式如下:
range(start, end, step) # start是起始值,end是终止值,step是间隔值
然后会从起始值开始产生等差数列,每次间隔step时产生新数值元素,到end-1为止,下列是产生2~11间的偶数。
此外,step值也可以是负值,此时起始值必须大于终止值。
7-2-4 活用range( )应用
程序设计时我们也可以直接应用range( ),可以产生程序精简的效果。
程序实例ch7_12.py:输入一个正整数n,这个程序会输出从1加到n的总和。
# ch7_12.py
start = 2
end = 9
step = 2
number1 = list(range(start, end, step))
print("当start值是%2d, end值是%2d, step值是%2d时的range( )列表元素:" % (start, end, step))
for number in range(start,end,step):
print(number)
start = -2
end = 9
step = 3
number2 = list(range(start, end, step))
print("当start值是%2d, end值是%2d, step值是%2d时的range( )列表元素:" % (start, end, step))
for number in range(start,end,step):
print(number)
start = 5
end = -5
step = -3
number3 = list(range(start, end, step))
print("当start值是%2d, end值是%2d, step值是%2d时的range( )列表元素:" % (start, end, step))
for number in range(start,end,step):
print(number)
执行结果
当start值是 2, end值是 9, step值是 2时的range( )列表元素:
2
4
6
8
当start值是-2, end值是 9, step值是 3时的range( )列表元素:
-2
1
4
7
当start值是 5, end值是-5, step值是-3时的range( )列表元素:
5
2
-1
-4
上述程序笔者使用了可迭代对象的内置函数sum执行总和的计算,它的工作原理并不是一次预留储存1, 2, … 10的内存空间,然后执行运算,而是只有一个内存空间,每次将迭代的指针放在此空间,然后执行sum( )运算,可以增加工作效率并节省内存空间。
程序实例ch7_13.py:建立一个整数平方的列表,为了避免数值太大,若是输入值大于10,此大于10的数值将被设为10。
# ch7_13.py
n = int(input("请输入整数:"))
number = list(range(n + 1))
total = sum(number)
print("从1到%d的总和是 = " % n, total)
执行结果
请输入整数:12
从1到12的总和是 = 78
对于上述代码而言,下面我们使用“**”代替乘方运算,同时第6和第7行使用更精简的方式。
程序实例ch7_14.py:用更精简方式设计ch7_13.py。
# ch7_14.py
n = int(input("请输入整数:"))
number = list(range(n + 1)) # 建立列表
total = 0 # 总计
for i in number:
total += i
print("从1到%d的总和是 = " % n, total)
执行结果 与ch7_13.py相同。
7-2-5 列表生成(list generator)的应用
其实我们还可以进一步简化程序实例ch7_14.py,这个方式是将for循环与加入列表的代码浓缩为一行,对上述程序而言,可以将第5和6行浓缩为一行,在说明实例前先看基本语法。基本语法如下:
新列表 = [表达式 for 项目 in 可迭代对象]
上述语法观念是,将每个可迭代对象套入表达式,每次产生一个列表元素。如果将第5~6行转成上述语法,内容如下:
square = [num ** 2 for num in range(1, n+1)]
此外,用这种方式设计时,我们可以省略第2行(建立空列表)。
程序实例ch7_15.py:重新设计ch7_14.py,进阶列表生成的应用。
# ch7_15.py
n = int(input("请输入整数:"))
total = 0 # 总计
for i in range(1, n+1):
total += i
print("从1到%d的总和是 = " % n, total)
执行结果 与ch7_14.py相同。
程序实例ch7_16.py:毕达哥拉斯直角三角形(A Pythagorean triple)定义,其实这是中学数学的勾股定理,基本观念是直角三角形两边长的平方和等于斜边的平方,如下:
a2 + b2 = c2 # c是斜边长
这个定理我们可以用(a, b, c)方式表达,最著名的实例是(3,4,5),小括号是数组的表达方式,我们尚未介绍,所以本节使用[a,b,c]列表表示。这个程序会生成0~19间符合定义的a、b、c列表值。
# ch7_16.py
squares = [] # 建立空列表
n = int(input("请输入整数:"))
if n > 10 : n = 10 # 最大值是10
for num in range(1, n+1):
value = num * num # 元素平方
squares.append(value) # 加入列表
print(squares)
执行结果
请输入整数:12
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
程序实例ch7_17.py:在数学的使用中会碰上下列数学定义。
A * B = {(a, b)}:a 属于A元素,b属于B元素
我们可以用下列程序生成这类的列表。
# ch7_17.py
squares = [] # 建立空列表
n = int(input("请输入整数:"))
if n > 10 : n = 10 # 最大值是10
for num in range(1, n+1):
squares.append(num ** 2) # 加入列表
print(squares)
执行结果
请输入整数:12
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
7-2-6 打印含列表元素的列表
这个小节的观念称为list unpacking,这个程序会从每个列表中拉出color和shape的列表元素值。
程序实例ch7_18.py:简化上一个程序,然后列出列表内每个元素列表值。
# ch7_18.py
n = int(input("请输入整数:"))
if n > 10 : n = 10 # 最大值是10
squares = [num ** 2 for num in range(1, n+1)]
print(squares)
执行结果
请输入整数:12
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
7-2-7 生成含有条件的列表
这时语法如下:
新列表 = [表达式 for 项目 in 可迭代对象 if 条件式]
下列是用传统方式生成1, 3, … , 9的列表:
下列是使用Python精神,设计含有条件式的列表生成程序。
7-3 进阶的for循环应用
7-3-1 嵌套for循环
一个循环内有另一个循环,我们称这是嵌套循环。如果外循环要执行n次,内循环要执行m次,则整个循环执行的次数是n*m次,设计这类循环时要特别注意下列事项:
外层循环的索引值与内层循环的索引值必须不同。
程序代码的内缩一定要小心。
下列是嵌套循环基本语法:
for 变量 in 对象: # 外层for循环
…
for 变量 in 对象: # 内层for循环
…
下列将用实例说明。
程序实例ch7_19.py:打印9*9的乘法表。
# ch7_19.py
for i in range(1, 10):
for j in range(1, 10):
result = i * j
print("%d*%d=%-3d" % (i, j, result), end=" ")
print() # 换行输出
执行结果
1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
2*1=2 2*2=4 2*3=6 2*4=8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=18
3*1=3 3*2=6 3*3=9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27
4*1=4 4*2=8 4*3=12 4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 5*6=30 5*7=35 5*8=40 5*9=45
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 6*7=42 6*8=48 6*9=54
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 7*8=56 7*9=63
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 8*9=72
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
上述程序第5行,%-3d主要是供result使用,表示每一个输出预留3格,同时靠左输出。同一行End=“”则是设定,输出完空一格,下次输出不换行输出。当内层循环执行完一次,则执行第6行,这是外层循环叙述,主要是设定下次换行输出,相当于下次再执行内层循环时换行输出。
程序实例ch7_20.py:绘制直角三角形。
# ch7_20.py
for i in range(1, 10):
for j in range(1, 10):
if j <= i:
print("aa", end="")
print() # 换行输出
执行结果
aa
aaaa
aaaaaa
aaaaaaaa
aaaaaaaaaa
aaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaa
7-3-2 强制离开for循环-break指令
在设计for循环时,如果期待某些条件发生时可以离开循环,可以在循环内执行break指令,即可立即离开循环,这个指令通常是和if语句配合使用。下列是常用的语法格式:
下列是流程图,其中在for循环内的if条件判断,也许前方有程序代码区块1、if条件内有程序代码区块2或是后方有程序代码区块3,只要if条件判断是True,则执行if条件内的程序代码区块2后,可立即离开循环。
例如,设计一个比赛,可以将参加比赛者的成绩列在列表内,如果想列出前20名参加决赛,可以设定for循环当选取20名后,即离开循环,此时就可以使用break功能。
程序实例ch7_21.py:输出一系列数字元素,当数字为5时,循环将终止执行。
# ch7_21.py
print("测试1")
for digit in range(1, 11):
if digit == 5:
break
print(digit, end=', ')
print( )
print("测试2")
for digit in range(0, 11, 2):
if digit == 5:
break
print(digit, end=', ')
执行结果
测试1
1, 2, 3, 4,
测试2
0, 2, 4, 6, 8, 10,
上述在第一个列表的测试中(第3至6行),当碰到列表元素是5时,循环将终止,所以只有列出“1, 2, 3, 4,”元素。在第二个列表的测试中(第9至12行),当碰到列表元素是5时,循环将终止,可是这个列表元素中没有5,所以整个循环可以正常执行到结束。
程序实例ch7_22.py:列出球员名称,列出多少个球员则是由屏幕输入,这个程序同时设定,如果屏幕输入的人数大于列表的球员数时,自动将所输入的人数降为列表的球员数。
# ch7_22.py
players = ['Curry', 'Jordan', 'James', 'Durant', 'Obama', 'Kevin', 'Lin']
n = int(input("请输入人数 = "))
if n > len(players) : n = len(players) # 列出人数不大于列表元素数
index = 0 # 索引
for player in players:
if index == n:
break
print(player, end=" ")
index += 1 # 索引加1
执行结果
请输入人数 = 12
Curry Jordan James Durant Obama Kevin Lin
7-3-3 for循环暂时停止不往下执行–continue指令
在设计for循环时,如果期待某些条件发生时可以不往下执行循环内容,此时可以用continue指令,这个指令通常是和if语句配合使用。下列是常用的语法格式:
下列是流程图,相当于如果发生if条件判断是True时,则不执行程序代码区块3内容。
程序实例ch7_23.py:有一个列表scores纪录James的比赛得分,设计一个程序可以列出James有多少场次得分大于或等于30分。
# ch7_23.py
scores = [33, 22, 41, 25, 39, 43, 27, 38, 40]
games = 0
for score in scores:
if score < 30: # 小于30则不往下执行
continue
games += 1 # 场次加1
print("有%d场得分超过30分" % games)
执行结果
有6场得分超过30分
程序实例ch7_24.py:有一个列表players,这个列表的元素也是列表,包含球员名字和身高数据,列出所有身高是200(含)公分以上的球员数据。
# ch7_24.py
players = [['James', 202],
['Curry', 193],
['Durant', 205],
['Jordan', 199],
['David', 211]]
for player in players:
if player[1] < 200:
continue
print(player)
执行结果
['James', 202]
['Durant', 205]
['David', 211]
对于上述for循环而言,每次执行第7行时,player的内容是players的一个元素,而这个元素是一个列表,例如:第一次执行时player内容是如下:
[‘James', 202]
执行第8行时,player[1]的值是202。由于if判断的结果是False,所以会执行第10行的print(player)指令,其他可依次类推。
7-3-4 for … else循环
在设计for循环时,如果期待所有的if叙述条件是False时,在最后一次循环后,可以执行特定程序区块指令,可使用这个叙述,这个指令通常是和if和break语句配合使用。下列是常用的语法格式:
下列是流程图,如果最后一次循环if条件表达式仍是False时,才会执行程序代码区块4。
其实这个语法很适合传统数学中测试某一个数字n是否是质数,质数的条件是:
- 2是质数。
- n不可被2至n-1的数字整除。
程序实例ch7_25.py:质数测试的程序,如果所输入的数字是质数则列出是质数,否则列出不是质数。
# ch7_25.py
num = int(input("请输入大于1的整数做质数测试 = "))
if num == 2: # 2是质数所以直接输出
print("%d是质数" % num)
else:
for n in range(2, num): # 用2 .. num-1当除数测试
if num % n == 0: # 如果整除则不是质数
print("%d不是质数" % num)
break # 离开循环
else: # 否则是质数
print("%d是质数" % num)
执行结果
请输入大于1的整数做质数测试 = 3
3是质数
7-4 while循环
这也是一个循环,基本上循环会一直执行直到条件运算为False才会离开循环,所以设计while循环时一定要设计一个条件可以离开循环,相当于让循环结束。程序设计时,如果忘了设计条件可以离开循环,程序造成无限循环状态,此时可以同时按Ctrl+C键,中断程序的执行离开无限循环的陷阱。
一般while循环常应用在不知道循环何时可以结束的状况,for循环在使用时是早已经知道循环即将执行的次数。不过我们也可以透过一些技巧,让while循环也可以应用在已经知道循环即将执行的次数上。它的语法格式如下:
while 条件运算:
程序区块
下列是while循环语法流程图。
7-4-1 基本while循环
程序实例ch7_26.py:这个程序会输出你所输入的内容,当输入q时,程序才会执行结束。
# ch7_26.py
msg1 = '人机对话专栏,告诉我心事吧,我会重复你告诉我的心事!'
msg2 = '输入 q 可以结束对话'
msg = msg1 + '\n' + msg2 + '\n' + '= '
input_msg = '' # 默认为空字符串
while input_msg != 'q':
input_msg = input(msg)
print(input_msg)
执行结果
人机对话专栏,告诉我心事吧,我会重复你告诉我的心事!
输入 q 可以结束对话
= 哈哈
哈哈
上述程序最大的缺点是,当输入q时,程序也将输出q,然后才结束while循环,我们可以使用下列第8行增加if条件判断方式改良。
程序实例ch7_27.py:改良程序ch7_26.py,当输入q时,不再输出q。
# ch7_27.py
msg1 = '人机对话专栏,告诉我心事吧,我会重复你告诉我的心事!'
msg2 = '输入 q 可以结束对话'
msg = msg1 + '\n' + msg2 + '\n' + '= '
input_msg = '' # 默认为空字符串
while input_msg != 'q':
input_msg = input(msg)
if input_msg != 'q': # 如果输入不是q才输出讯息
print(input_msg)
执行结果
输入 q 可以结束对话
= 哈哈
哈哈
人机对话专栏,告诉我心事吧,我会重复你告诉我的心事!
输入 q 可以结束对话
= 呵呵
呵呵
人机对话专栏,告诉我心事吧,我会重复你告诉我的心事!
输入 q 可以结束对话
=
上述程序尽管可以完成工作,但是当我们在设计大型程序时,如果可以有更明确的标记记录程序是否继续执行将更佳,下列笔者将用一个布尔变量值active当作标记,如果是True则while循环继续,否则while循环结束。
程序实例ch7_28.py:改良ch7_27.py程序的可读性,使用标记active记录是否循环继续。
# ch7_28.py
msg1 = '人机对话专栏,告诉我心事吧,我会重复你告诉我的心事!'
msg2 = '输入 q 可以结束对话'
msg = msg1 + '\n' + msg2 + '\n' + '= '
active = True
while active: # 循环进行直到active是False
input_msg = input(msg)
if input_msg != 'q': # 如果输入不是q才输出讯息
print(input_msg)
else:
active = False # 输入是q所以将active设为False
执行结果 与ch7_27.py相同。
程序实例ch7_29.py:猜数字游戏,程序第2行用变量answer存储欲猜的数字,程序执行时用变量guess存储所猜的数字。
# ch7_29.py
answer = 30 # 正确数字
guess = 0 # 设定所猜数字的初始值
while guess != answer:
guess = int(input("请猜1-100间的数字 = "))
if guess > answer:
print("请猜小一点")
elif guess < answer:
print("请猜大一点")
else:
print("恭喜答对了")
执行结果
请猜1-100间的数字 = 23
请猜大一点
请猜1-100间的数字 = 55
请猜小一点
请猜1-100间的数字 = 50
请猜小一点
请猜1-100间的数字 = 40
请猜小一点
请猜1-100间的数字 = 35
请猜小一点
请猜1-100间的数字 = 30
恭喜答对了
下列是使用while循环,已经知道要执行多少次循环了的实例。
程序实例ch7_30.py:while循环索引值变化的观察。
# ch7_30
index = 1
while index <= 5:
print("第 %d 次while循环" % index)
index += 1
执行结果
第 1 次while循环
第 2 次while循环
第 3 次while循环
第 4 次while循环
第 5 次while循环
7-4-2 嵌套while循环
while循环也允许嵌套循环,此时的语法格式如下:
while 条件运算: # 外层while循环
…
while 条件运算: # 内层while循环
…
程序实例ch7_31.py:使用while循环重新设计ch7_19.py,打印九九乘法表。
# ch7_31.py
i = 1 # 设定i初始值
while i <= 9: # 当i大于9跳出外层循环
j = 1 # 设定j初始值
while j <= 9: # 当j大于9跳出内层循环
result = i * j
print("%d*%d=%-3d" % (i, j, result), end=" ")
j += 1 # 内层循环加1
print() # 换行输出
i += 1 # 外层循环加1
执行结果 与ch7_19.py相同。
7-4-3 强制离开while循环-break指令
7-3-2节所介绍的break指令与观念,也可以应用在while循环。在设计while循环时,如果期待某些条件发生时可以离开循环,可以在循环内执行break指令立即离开循环,这个指令通常是和if语句配合使用。下列是常用的语法格式:
程序实例ch7_32.py:这个程序会先建立while无限循环,如果输入q,则可跳出这个while无限循环。程序内容主要是要求输入水果,然后输出此水果。
# ch7_32.py
msg1 = '人机对话专栏,请告诉我妳喜欢吃的水果!'
msg2 = '输入 q 可以结束对话'
msg = msg1 + '\n' + msg2 + '\n' + '= '
while True: # 这是while无限循环
input_msg = input(msg)
if input_msg == 'q': # 输入q可用break跳出循环
break
else:
print("我也喜欢吃 %s " % input_msg.title( ))
执行结果
人机对话专栏,请告诉我妳喜欢吃的水果!
输入 q 可以结束对话
= 香蕉
我也喜欢吃 香蕉
人机对话专栏,请告诉我妳喜欢吃的水果!
输入 q 可以结束对话
=
程序实例ch7_33.py:使用while循环重新设计ch7_22.py。
# ch7_33.py
players = ['Curry', 'Jordan', 'James', 'Durant', 'Obama', 'Kevin', 'Lin']
n = int(input("请输入人数 = "))
if n > len(players) : n = len(players) # 列出人数不大于串行元素数
index = 0 # 索引index
while index < len(players): # 是否index在串行长度范围
if index == n: # 是否达到想列出的人数
break
print(players[index], end=" ")
index += 1 # 索引index加1
执行结果 与ch7_22.py相同。
上述程序第6行的“index < len(players)”相当于是语法格式的条件表达式A,控制循环是否终止。程序第7行的“index == n”相当于是语法格式的条件表达式B,可以控制是否中途离开while循环。
7-4-4 while循环暂时停止不往下执行-continue指令
在设计while循环时,如果期待某些条件发生时可以不往下执行循环内容,此时可以用continue指令,这个指令通常是和if语句配合使用。下列是常用的语法格式:
程序实例ch7_34.py:列出1至10之间的偶数。
# ch7_34.py
index = 0
while index <= 10:
index += 1
if ( index % 2 != 0 ): # 测试是否奇数
continue # 不往下执行
print(index) # 输出偶数
执行结果
2
4
6
8
10
7-4-5 while循环条件表达式与对象
while循环的条件表达式也可与对象(列表、元组或字典)配合使用,此时它的语法格式如下:
while 条件表达式: # 与有关的条件表达式
程序区块
程序实例ch7_35.py:删除列表内的apple字符串,程序第5行,只要在fruits列表内可以找到变量apple,就会传回True,循环将继续。
# ch7_35.py
fruits = ['apple', 'orange', 'apple', 'banana', 'apple']
fruit = 'apple'
print("删除前的fruits", fruits)
while fruit in fruits: # 只要列表内有apple循环就继续
fruits.remove(fruit)
print("删除后的fruits", fruits)
执行结果
删除前的fruits ['apple', 'orange', 'apple', 'banana', 'apple']
删除后的fruits ['orange', 'banana']
程序实例ch7_36.py:有一个列表buyers,此列表内含购买者和消费金额,如果购买金额超过或达到1000元,则归类为VIP买家vipbuyers列表。否则是Gold买家goldbuyers列表。
# ch7_36.py
buyers = [['James', 1030], # 建立买家购买纪录
['Curry', 893],
['Durant', 2050],
['Jordan', 990],
['David', 2110]]
goldbuyers = [] # Gold买家列表
vipbuyers =[] # VIP买家列表
while buyers: # 执行买家分类循环分类完成循环才会结束
index_buyer = buyers.pop()
if index_buyer[1] >= 1000: # 用1000圆执行买家分类条件
vipbuyers.append(index_buyer) # 加入VIP买家列表
else:
goldbuyers.append(index_buyer) # 加入Gold买家列表
print("VIP 买家资料", vipbuyers)
print("Gold买家资料", goldbuyers)
执行结果
VIP 买家资料 [['David', 2110], ['Durant', 2050], ['James', 1030]]
Gold买家资料 [['Jordan', 990], ['Curry', 893]]
上述程序第9行只要列表不是空列表,while循环就会一直执行。
7-4-6 pass
pass指令是什么事也不做,如果我们想要建立一个无限循环可以使用下列写法。
while True:
pass
不过不建议这么做,这会让程序进入无限循环。这个指令有时候会用在设计一个循环或函数(将在第11-8节解说)尚未完成时,先放pass,未来再用完整程序代码取代。
程序实例ch7_37.py:pass应用在循环的实例,这个程序的循环尚未设计完成,所以笔者先用pass处理。
# ch7_37.py
schools = ['三峡大学', '长江大学', '武汉大学']
for school in schools:
pass
执行结果
没有任何数据输出。
7-5 enumerate对象使用for循环解析
延续6-11节的enumerate对象可知,这个对象是由计数值与元素值配对出现: 计数值 元素值
所以我们可以使用for循环将每一个计数值与元素值解析出来。
程序实例ch7_38.py:继续设计ch6_48.py,将enumerate对象的计数值与元素值解析出来。
# ch7_38.py
drinks = {"coffee", "tea", "wine"}
# 解析enumerate物件
for drink in enumerate(drinks): # 数值初始是0
print(drink)
for count, drink in enumerate(drinks):
print(count, drink)
print("****************")
# 解析enumerate物件
for drink in enumerate(drinks, 10): # 数值初始是10
print(drink)
for count, drink in enumerate(drinks, 10):
print(count, drink)
执行结果
(0, 'wine')
(1, 'tea')
(2, 'coffee')
0 wine
1 tea
2 coffee
****************
(10, 'wine')
(11, 'tea')
(12, 'coffee')
10 wine
11 tea
12 coffee
上述程序第6行观念如下:
由于enumerate(drinks)产生的enumerate对象是配对存在,可以用2个变量遍历这个对象,只要仍有元素尚未被遍历循环就会继续。