开源图书《Python完全自学教程》6.5while循环语句

2022-07-06 15:54:33 浏览数 (2)

6.5 while 循环语句

for 循环必须以可迭代对象作为被循环的对象,while 循环则不同,它是依据一定的条件进行循环,即只要满足某条件,循环体中的语句“总跑着”。

6.5.1 基本格式

while 循环语句的基本格式是:

代码语言:javascript复制
while <expression>:
    <statements>

如果 <expression> 的布尔值是 True ,则执行循环体内的语句块 <statements>——依然是以缩进标记语句块。

代码语言:javascript复制
>>> n = 3
>>> while n > 0:
...     n -= 1
...     print(n)
...
2
1
0

在这段代码中,n 的初始值是 3 ,则 while 后的表达式 n > 0 的布尔值是 True ,于是执行下面的语句块。执行 n -= 1n 的值为 2 (见 print(n) 结果),n > 0 的布尔值还是 True ,继续执行循环体中的语句块,直到 n = 0 ,表达式 n > 0 的布尔值是 False ,停止循环。

再如:

代码语言:javascript复制
>>> lst = ['java', 'python', 'julia']
>>> while lst:
...     print(lst.pop())
...
julia
python
java

依然要判断 while 后面的表达式 lst 的布尔值,因为在上一行定义了该列表不为空,故其布尔值是 True ,于是执行循环体中的语句块。lst.pop() 的功能是删除列表中最后的成员并返回删除对象,直到列表为空,其布尔值为 False ,则终止循环。

如果有兴趣在交互模式中输入下面的代码,会发现一个“神奇”的现象:

代码语言:javascript复制
>>> while 1:
...     print("laoqi")
...

观察到了吗?不看到终端不停地打印 'laoqi' ,就很难体会到什么叫做“死循环”——“循环到死”,无法靠程序自身的控制终止循环,也称“无限循环”。要停止上述“死循环”,最简单的方法就是关掉终端窗口。

6.5.2 break 和 continue 语句

在 Python 关键词中,breakcontinue 两个关键词构成了两个语句:

  • break 语句:终止循环,并跳转到循环语句下面的语句;
  • continue 语句:跳过此语句后面的循环体中的其他语句,回到循环的开始,并评估是否满足循环条件。

这两个语句可以用于 while 循环,也可以用于 for 循环。以 while 循环为例,其作用效果如图6-5-1所示。

图6-5-1 brak 和 continue 语句

用 break 语句将前面“死循环”的程序改造如下:

代码语言:javascript复制
#coding:utf-8
'''
whileloop.py
'''
n = 0
while 1:
    n  = 1
    if n >= 3:       # (1)
        break
    print('laoqi')

print('loop end')    # (2)

执行效果:

代码语言:javascript复制
% python whileloop.py 
laoqi
laoqi
loop end

对照程序代码和执行结果,当满足注释(1)时,即执行其下的 break ,从而避免无限循环,并跳转到循环语句下面的注释(2)。

下面写一个“猜数游戏”的程序,要求:(1)计算机随机生成一个100以内的正整数;(2)用户通过键盘输入数字,猜测计算机所生成的随机数。注意,用户的输入次数不进行限制。

相较于前述写过的程序,现在这个要求比较复杂,算是一个“大型程序”了。不过,不论面对多么复杂的程序,都要将需求分析清楚——本程序需求已明确,再针对需求制定实现策略。

  • 生成随机数:用标准库的 random 模块;
  • 获得用户输入的数字:用 input() 函数;
  • 实现不限次数的操作:用 while 循环语句;
  • 判断用户的输入是否等于生成的随机数:用 if 语句;
  • 猜中了终止循环:用 break 语句。

接下来的工作,就是运用已经学过的知识,将上述策略编写成可执行的程序。建议读者先自己编写,而后与下面的示例代码进行对照,取长补短。此处的代码示例仅仅是一种实现方式,并不是标准答案。

代码语言:javascript复制
#coding:utf-8
'''
guessnumber.py
'''

import random
number = random.randint(1,100)
guess = 0
while True: 
    num_input = input("please input one integer that is in 1~100:") 
    guess  = 1
    if not num_input.isdigit():
        print("Please input interger.") 
    elif int(num_input) < 0 or int(num_input) >= 100:
        print("The number should be in 1 to 100.") 
    else:
        if number == int(num_input): 
            print(f"OK, you’ve done well.It is only {guess} times.") 
            break
        elif number > int(num_input): 
            print("your number is smaller.") 
        else: 
            print("your number is bigger.")

执行此程序,想一想怎么猜?观察我的猜测过程:

代码语言:javascript复制
% python guessnumber.py
please input one integer that is in 1~100:50
your number is bigger.
please input one integer that is in 1~100:25
your number is smaller.
please input one integer that is in 1~100:37
your number is smaller.
please input one integer that is in 1~100:44
your number is smaller.
please input one integer that is in 1~100:47
your number is bigger.
please input one integer that is in 1~100:46
your number is bigger.
please input one integer that is in 1~100:45
OK, you’ve done well.It is only 7 times.

这个猜的过程,其实运用了一种简单的算法——二分查找算法(Binary Search Algorithm)。当然,运气好了,随便输入一个就能猜中,“蒙着猜”毕竟耗费的时间不稳定,而运用二分查找算法,你可以估计出最坏的时间复杂度。

由图6-5-1可知,另外一个关键词发起的 continue 语句,会略过此后的语句,回到循环的初始判断行,例如:

代码语言:javascript复制
#coding:utf-8
'''
whilecontinue.py
'''
a = 11
while a > 0:
    a -= 1
    if a % 2 == 0:
        continue  # (3)
        print(a)  # (4)
    else:
        print(a)  # (5)

还是先看调试结果,再解释必要的部分。

代码语言:javascript复制
% python whilecontinue.py
9
7
5
3
1

在 while 循环语句块内,当 a 是偶数时,执行注释(3)的 continue 语句,依据图6-5-1所示,略过其后的注释(4),即不打印偶数,然后转到 while 循环的开始,满足条件即再自减 1 ,则 a 变为奇数,执行注释(5),将奇数打印出来。于是得到了上述只显示奇数的执行结果。

break 语句和 continue 语句不仅仅可以用在 while 循环中,也能用于 for 循环,其作用亦然。

代码语言:javascript复制
>>> for i in range(10):
...     if i % 2 == 0:
...         continue
...         print(i)
...     else:
...         print(i)
...
1
3
5
7
9

这是 continue 语句在 for 循环中的应用举例,读者可以对照前述 whilecontinue.py 中的程序理解。

代码语言:javascript复制
>>> for i in range(1, 10):
...     if i % 5 == 0:
...         break
...     else:
...         print(i)
...
1
2
3
4

注意,上述代码中的 range(1, 10) ——如果是 rang(10) 会是什么结果?为什么?

6.5.3 else 分支

在6.3.1节的图6-3-1中,显示 for 循环有一个可选的 else 分支。对于 while 循环,也可以有此分支,语法格式为:

代码语言:javascript复制
while <expression>:
    statements
else:
    additional_statements

下面就以 while 循环为例,理解 else 分支的作用。例如:

代码语言:javascript复制
>>> n = 5
>>> while n > 0:
...     n -= 1
...     print(n)
... else:
...     print("this is else")
...
4
3
2
1
0
this is else

对照程序和上面的语法格式,当 n 自减到 0 时,n > 0 的布尔值是 False ,即不再执行 while 循环,则开始执行 else 分支下的语句。这段程序中没有 break 中断循环——循环是寿终正寝的。不然,使用 break 语句让循环“夭折”,会如何?

代码语言:javascript复制
>>> n = 5
>>> while n > 0:
...     n -= 1
...     print(n)
...     if n == 2:
...         break
... else:
...     print('this is else')
...
4
3
2

在6.5.2节中学习 break 语句的时候,图6-5-1中显示,遇到 break 后就跳到 while 循环后面的语句。上述程序结果说明,如果 while 后面有 else 分支, break 也会跳过它。

通过上述对比,了解了 else 分支的作用,但是,另外一个问题就来了,如果写成:

代码语言:javascript复制
while <expression>:
    statements

additional_statements

与上面包含 else 分支的语法有什么区别?

通过含有 break 的程序,就能看出区别:如果不使用 else 分支,additional_statements 的语句会总被执行,哪怕循环“夭折”也会执行。

事实上, else 分支在 while 循环中并非必要,Python 发明者吉多·范罗索姆甚至想剔除 while 的 else 分支。

在 for 循环中,else 分支会有如何表现?看下面的示例:

代码语言:javascript复制
#coding:utf-8
'''
filename: forelse.py
'''
nums = [60, 70, 30, 110, 90]
found = False
for n in nums:
    if n > 100:
        found = True
        print("There is a number bigger than 100")
        break

if not found:     # (6)
    print("Not found!")

判断列表 nums 中是否有大于 100 的整数,若有,则 found = True ,并执行 break 结束循环。那么,此时注释(6)的条件就不满足了。否则,如果列表 nums 中没有使 n > 100 成立的整数,则 found = Fasle ,注释(6)的条件语句就会执行。显然,程序中的 found 就相当于一个“开关”(常说的“flag”)。如果用 else 分支,则可以省掉这个“开关”。

代码语言:javascript复制
nums = [60, 70, 30, 110, 90]
for n in nums:
    if n > 100:
        print("There is a number bigger than 100")
        break
else:
    print("Not found!")

之所以能省掉 found ,也是因为循环被 break 后,else 分支不再执行。若修改 nums 中的数值,使 if n > 100 语句不执行,当循环完毕,则执行 else 分支——读者可以自行测试。由此可见,else 分支不论在 while 循环还是 for 循环,执行它的条件都是一样的。

0 人点赞