跳转至

Topic 7.2 - while 循环的进阶用法

1. while 循环的嵌套

(1) while 循环的嵌套使用

while 循环也可以嵌套使用,即在一个 while 循环体内再包含另一个 while 循环,来实现更复杂的逻辑和功能。

嵌套 while 循环的基本语法如下:

while 条件1:
    循环体1
    while 条件2:
        循环体2
    循环体1的其他代码
  • 在这段代码中,循环体1 是外层循环的代码块,循环体2 是内层循环的代码块
  • 当外层循环的条件 条件1True 时,进入外层循环体,执行 循环体1 的代码
  • 当执行到内层 while 条件2: 时,如果 条件2True,则进入内层循环体,执行 循环体2 的代码
  • 当内层循环全部执行完毕后,程序会回到外层循环体,继续执行 循环体1 的其他代码,然后重新评估外层循环的条件 条件1
  • 当外层循环来到第二圈时,内层循环又会从头重新开始执行一遍

我们来看一个简单的例子:

i = 0

while i < 3:
    print("外层循环计数", i)
    j = 0
    while j < 2:
        print("    内层循环计数", j)
        j = j + 1
    i = i + 1

print("循环结束")
外层循环计数 0
    内层循环计数 0
    内层循环计数 1
外层循环计数 1
    内层循环计数 0
    内层循环计数 1
外层循环计数 2
    内层循环计数 0
    内层循环计数 1
循环结束

在这个例子中:

  • 外层循环第1次判断时 i 值为 00 < 3True,进入外层循环,然后打印 外层循环计数 0,之后将 j 初始化为 0

    • 内层循环第1次判断时 j 值为 00 < 2True,进入内层循环,然后打印 内层循环计数 0,之后将 j 增加 1 变为 1
    • 内层循环第2次判断时 j 值为 11 < 2True,进入内层循环,然后打印 内层循环计数 1,之后将 j 增加 1 变为 2
    • 内层循环第3次判断时 j 值为 22 < 2False,退出内层循环,

    回到外层循环体,之后将 i 增加 1 变为 1

  • 外层循环第2次判断时 i 值为 11 < 3True,进入外层循环,然后打印 外层循环计数 1,之后将 j 初始化为 0

    • 内层循环第1次判断时 j 值为 00 < 2True,进入内层循环,然后打印 内层循环计数 0,之后将 j 增加 1 变为 1
    • 内层循环第2次判断时 j 值为 11 < 2True,进入内层循环,然后打印 内层循环计数 1,之后将 j 增加 1 变为 2
    • 内层循环第3次判断时 j 值为 22 < 2False,退出内层循环,

    回到外层循环体,之后将 i 增加 1 变为 2

  • 外层循环第3次判断时 i 值为 22 < 3True,进入外层循环,然后打印 外层循环计数 2,之后将 j 初始化为 0

    • 内层循环第1次判断时 j 值为 00 < 2True,进入内层循环,然后打印 内层循环计数 0,之后将 j 增加 1 变为 1
    • 内层循环第2次判断时 j 值为 11 < 2True,进入内层循环,然后打印 内层循环计数 1,之后将 j 增加 1 变为 2
    • 内层循环第3次判断时 j 值为 22 < 2False,退出内层循环,

    回到外层循环体,之后将 i 增加 1 变为 3

  • 外层循环第4次判断时 i 值为 33 < 3False,退出外层循环

  • 程序继续执行 print("循环结束"),打印 循环结束

(2) while 循环嵌套中的 breakcontinue

在嵌套的 while 循环中,breakcontinue 语句的作用范围仅限于它们所在的循环体:

  • break 语句会终止它所在的最近一层循环,无法同时终止多层循环
  • continue 语句会跳过它所在的最近一层循环的当前迭代,进入下一次迭代,无法同时影响多层循环

我们来看一个例子:

i = 0

while i < 3:
    print("外层循环计数", i)
    j = 0
    while j < 5:
        print("    内层循环计数", j)
        if j == 2:
            break
        j = j + 1
    i = i + 1

print("循环结束")
外层循环计数 0
    内层循环计数 0
    内层循环计数 1
    内层循环计数 2
外层循环计数 1
    内层循环计数 0
    内层循环计数 1
    内层循环计数 2
外层循环计数 2
    内层循环计数 0
    内层循环计数 1
    内层循环计数 2
循环结束

这里我们可以看到,break 语句只终止了内层循环

  • 当内层循环被 break 终止后,程序回到外层循环体,继续执行外层循环
  • 而外层循环并没有受到影响,继续进行下一次迭代

我们来看一个使用两个 break 语句,来分别终止内层和外层循环的例子:

i = 0

while i < 3:
    print("外层循环计数", i)
    j = 0
    while j < 5:
        print("    内层循环计数", j)
        if j == 2:
            break
        j = j + 1
    if i == 1:
        break
    i = i + 1

print("循环结束")
外层循环计数 0
    内层循环计数 0
    内层循环计数 1
    内层循环计数 2
外层循环计数 1
    内层循环计数 0
    内层循环计数 1
    内层循环计数 2
循环结束

这里我们可以看到:

  • 内层循环被 break 终止后,程序回到外层循环体,继续执行外层循环
  • 当外层循环的 i 值为 1 时,触发外层循环的 break 语句,终止了外层循环

2. while 循环综合练习 - 打印九九乘法表

我们来看一个经典的 while 循环的例子:打印九九乘法表,我们期望的输出是:

1 * 1 = 1 1 * 2 = 2 2 * 2 = 4 1 * 3 = 3 2 * 3 = 6 3 * 3 = 9 1 * 4 = 4 2 * 4 = 8 3 * 4 = 12 4 * 4 = 16 1 * 5 = 5 2 * 5 = 10 3 * 5 = 15 4 * 5 = 20 5 * 5 = 25 1 * 6 = 6 2 * 6 = 12 3 * 6 = 18 4 * 6 = 24 5 * 6 = 30 6 * 6 = 36 1 * 7 = 7 2 * 7 = 14 3 * 7 = 21 4 * 7 = 28 5 * 7 = 35 6 * 7 = 42 7 * 7 = 49 1 * 8 = 8 2 * 8 = 16 3 * 8 = 24 4 * 8 = 32 5 * 8 = 40 6 * 8 = 48 7 * 8 = 56 8 * 8 = 64 1 * 9 = 9 2 * 9 = 18 3 * 9 = 27 4 * 9 = 36 5 * 9 = 45 6 * 9 = 54 7 * 9 = 63 8 * 9 = 72 9 * 9 = 81 我们先来分析以下这个问题的实现思路和关键问题:

  • 乘法表有9行9列,每个单元格的格式都是 行号 * 列号 = 乘积
  • 但是表格的右上角是空的,这个是如何实现的呢:我们会发现空的部分满足一个条件:列号 > 行号,我们可以在程序中加入这个判断
  • 如果每一个算式对应一个打印的话,同一行中的算式并没有换行,这个是怎么做到的呢:这个就可以使用到 print 函数的 end 参数
  • 另外一个问题是:如何做到算式之间的对齐呢:这个可以使用到 \t 转义字符

我们先尝试实现一个简单的版本,我们先不考虑对齐和右上角的问题,用 * 先来占位,打印一个 9 * 9 的表格:

  • 首先我们要考虑,如何实现行和列的逻辑呢,这就要使用到嵌套 while 循环了,外圈控制行,内圈控制列
  • 其次,在打印行的时候,并没有换行,整个一行打印完毕才会换行,这就说明内圈中的 print 是有 end 参数的,而换行是在外圈中实现的
  • 我们来看代码:
row = 1
while row <= 9:
    col = 1
    while col <= 9:
        print("*", end="")
        col += 1
    print()
    row += 1
*********
*********
*********
*********
*********
*********
*********
*********
*********

接着我们把末尾的空字符串换成 \t,来实现对齐:

row = 1
while row <= 9:
    col = 1
    while col <= 9:
        print("*", end="\t")
        col += 1
    print()
    row += 1
*   *   *   *   *   *   *   *   *   
*   *   *   *   *   *   *   *   *   
*   *   *   *   *   *   *   *   *   
*   *   *   *   *   *   *   *   *   
*   *   *   *   *   *   *   *   *   
*   *   *   *   *   *   *   *   *   
*   *   *   *   *   *   *   *   *   
*   *   *   *   *   *   *   *   *   
*   *   *   *   *   *   *   *   *

接着,我们来实现右上角空白的逻辑:

  • 右上角空白的逻辑是:列号 > 行号
  • 那么左下角有数字的逻辑就是:列号 <= 行号
  • 这样的话,内圈循环的判断条件就不再是 col <= 9 了,而是 col <= row
  • 我们来看代码:
row = 1
while row <= 9:
    col = 1
    while col <= row:
        print("*", end="\t")
        col += 1
    print()
    row += 1
*   
*   *   
*   *   *   
*   *   *   *   
*   *   *   *   *   
*   *   *   *   *   *   
*   *   *   *   *   *   *   
*   *   *   *   *   *   *   *   
*   *   *   *   *   *   *   *   *

最后,我们把 * 替换成 行号 * 列号 = 乘积 的格式,就大功告成:

row = 1
while row <= 9:
    col = 1
    while col <= row:
        print(f"{col} * {row} = {col * row}", end="\t")
        col += 1
    print()
    row += 1
1 * 1 = 1   
1 * 2 = 2   2 * 2 = 4   
1 * 3 = 3   2 * 3 = 6   3 * 3 = 9   
1 * 4 = 4   2 * 4 = 8   3 * 4 = 12  4 * 4 = 16  
1 * 5 = 5   2 * 5 = 10  3 * 5 = 15  4 * 5 = 20  5 * 5 = 25  
1 * 6 = 6   2 * 6 = 12  3 * 6 = 18  4 * 6 = 24  5 * 6 = 30  6 * 6 = 36  
1 * 7 = 7   2 * 7 = 14  3 * 7 = 21  4 * 7 = 28  5 * 7 = 35  6 * 7 = 42  7 * 7 = 49  
1 * 8 = 8   2 * 8 = 16  3 * 8 = 24  4 * 8 = 32  5 * 8 = 40  6 * 8 = 48  7 * 8 = 56  8 * 8 = 64  
1 * 9 = 9   2 * 9 = 18  3 * 9 = 27  4 * 9 = 36  5 * 9 = 45  6 * 9 = 54  7 * 9 = 63  8 * 9 = 72  9 * 9 = 81

我们通过打印九九乘法表,简单地体会了一下程序开发的几个关键要素:

  • 需求分析:明确我们要实现什么功能,输出什么结果
  • 逻辑设计:在写代码之前,先分析实现这个功能需要哪些步骤,如何使用程序结构来实现
  • 版本迭代:从简单版本开始,逐步完善功能,最终实现目标