CC++ & Algorithm

Python 循环控制与综合应用

困难5
语言版本:C++PythonScratch(暂无)
概述:综合运用break、continue、else子句以及循环的嵌套,解决更复杂的问题。

循环控制进阶:让程序变得更聪明、更稳健

在编程中,循环帮我们重复做事情,但有时候我们需要在循环中途跳出来、跳过某次循环、或者只在循环正常结束时才执行某段代码。Python 提供了几个好用的工具:break、continue、以及循环的 else 子句。另外,把循环嵌套起来(放在另一个循环里面),再配合这些控制工具,就能解决很多实际生活中遇到的有趣问题。比如:老师点名(循环每一个学生),找零钱组合(循环所有硬币面值),猜数字游戏(循环猜拳直到猜对或次数用尽)。下面我们一步步来学习。


一、循环的 else 子句:只有完整跑完才“吹哨”

1. 它干什么用的?

for 和 while 循环后面都可以跟一个 else 块。这个 else 块只在 循环正常结束(没有因为 break 而提前退出)时才会执行。如果循环被 break 打断了,else 块就不执行。

想象一下:你每天放学后要在操场上跑 5 圈(循环 5 次)。如果中途下雨了,你躲进教室(相当于 break),那么跑圈就没有完成,老师不会给你奖励(else 不执行)。如果你坚持跑完了 5 圈(自然结束),老师就奖励你一颗糖(else 执行)。

2. 生活中的例子:检查全班同学有没有人忘带作业

你负责检查 10 个同学的作业。你从第 1 个问到第 10 个,如果遇到一个没带作业的,你就喊“有人没带作业!”然后停止检查(break)。如果全部检查完都没有人忘带,你就说“全班都带了!”(else 执行)。

代码实现:

students = ["小明", "小红", "小刚", "小丽", "小华"]
has_no_homework = True  # 假设每个同学都带了?实际上我们用循环检查

# 模拟检查过程:只有小丽没带作业
homework_status = {
    "小明": True,
    "小红": True,
    "小刚": True,
    "小丽": False,
    "小华": True
}

for student in students:
    if not homework_status[student]:  # 如果这个学生没带作业
        print(f"{student} 没带作业!")
        break
else:
    print("全班都带了作业!")

输出结果:

小丽 没带作业!

(没有执行 else 部分,因为被 break 打断了)

如果把小丽也改成带了作业,那么循环自然结束,就会打印“全班都带了作业!”。

3. 判断质数的经典例子(现有内容扩充)

判断一个数是不是质数,可以用 else 配合 for 循环。如果循环内部没有发现任何能整除的数(break 没执行),那么 else 就会执行,说明这个数是质数。

# 判断 2 到 9 哪些是质数
for i in range(2, 10):            # i 从 2 到 9
    for j in range(2, i):         # j 从 2 到 i-1
        if i % j == 0:            # 如果 i 能被 j 整除
            print(f"{i} 不是质数")
            break                  # 跳出内层循环
    else:
        print(f"{i} 是质数")

输出:

2 是质数
3 是质数
4 不是质数
5 是质数
6 不是质数
7 是质数
8 不是质数
9 不是质数

注意:else 是跟内层 for 对齐的,不是跟外层 for。它表示:内层循环如果完整跑完(没有 break),就说明 i 没有因数,是质数。


二、用标志变量优雅地跳出多重循环

有时候我们会遇到嵌套循环(循环里套循环),比如想要找一对数字 (x, y) 满足某个条件。当找到后,我们希望同时跳出内外两层循环。直接 break 只能跳出内层循环,外层还需要再判断一次才能跳出。解决办法有两种:

方法1:使用标志变量(flag)

设置一个变量 found,初始为 False,找到目标后就设为 True,然后在内层 break 后,在外层检查这个变量,再 break。

生活中的例子:你在抽屉里找钥匙,抽屉里又分好几个小格子。你一层一层翻,如果找到了,你就不需要再翻剩下的格子和抽屉了。这里的“找到”就是标志。

# 寻找两个正整数(都在 1-9 之间),它们的乘积等于 36
found = False  # 标志变量,初始为 False(还没找到)
for x in range(1, 10):
    for y in range(1, 10):
        if x * y == 36:
            print(f"找到组合:{x} x {y} = 36")
            found = True  # 标记已找到
            break          # 跳出内层循环
    if found:              # 如果已经找到了,就再跳出外层循环
        break

方法2:把循环放在函数里,用 return

当我们把嵌套循环放入一个函数,只要找到目标就可以用 return 直接退出函数,比标志变量更简洁。

def find_product(target):
    """在 1-9 范围内找两个数乘积等于 target,打印并返回第一个找到的组合"""
    for x in range(1, 10):
        for y in range(1, 10):
            if x * y == target:
                print(f"找到组合:{x} x {y} = {target}")
                return x, y  # 直接退出函数

find_product(36)

常见错误:新手容易忘记在外层也写一个 break,导致虽然内层跳出了,但外层还在继续循环,结果打印出多个组合。使用函数 return 可以避免这个麻烦。


三、综合案例:猜数字增强版(包含异常处理和 continue)

我们已经有一个猜数字游戏:程序随机生成一个 1~100 的数字,玩家有 5 次机会。如果猜对了就用 break 结束;如果 5 次都没猜对,循环正常结束,else 块提示机会用完。

现在我们要让程序更健壮:如果用户输入的不是数字(比如输入了“abc”),程序要提示“请输入数字”,并且 这次不算次数(让用户重新输入)。这就要用到 try-except 捕获异常(处理输入错误)和 continue 跳过本次循环。

完整代码(带中文注释)

import random

# 生成一个 1 到 100 之间的随机整数
secret = random.randint(1, 100)
max_chances = 5           # 最多可以猜 5 次
chances_used = 0          # 已经用了多少次(可选统计)

print("我想到一个1到100之间的数字,你有", max_chances, "次机会。")

while chances_used < max_chances:
    user_input = input(f"第 {chances_used+1} 次猜:")
    try:
        guess = int(user_input)   # 尝试将输入转为整数
    except ValueError:            # 如果转换失败(输入不是数字)
        print("请输入数字!这次不消耗次数。")
        continue                  # 跳过本次循环,不增加次数

    # 只有输入合法数字才消耗次数
    chances_used += 1

    if guess == secret:
        print("恭喜你,猜对了!")
        break                     # 猜对就结束
    elif guess > secret:
        print("大了")
    else:
        print("小了")
else:
    # 如果 while 循环因为条件不满足(次数用尽)正常结束,
    # 而且没有被 break 打断,就会执行 else
    print(f"机会用完了,数字是 {secret}。")

注意:这里把 for 改成了 while,因为 continue 后不希望增加 chances_used,用 for 会不好控制。实际上用 while 配合手动计数更灵活。else 在 while 循环中同样有效。


四、常见错误与提醒

  1. 忘记 else 是和 for 还是 if 对齐?
    else 是和最内层的 for 或 while 对齐的,不要习惯性地认为和 if 配对。例如判断质数时,else 是跟内层 for 的,不是跟 if 的。

  2. break 只能跳出当前一层循环。如果想跳出多层,必须用标志变量或函数 return。新手经常只在内层 break,以为外层也会停下,结果得到多余输出。

  3. continue 会跳过本次循环的剩余代码,但不会影响循环的迭代次数。在 for 循环中,它会直接进入下一次迭代;在 while 循环中,它回到条件判断。如果 while 里没正确更新计数器,可能导致死循环。比如上面猜数字例子中,如果用 for 并且 continue 后依然 attempt 会自增,就不能实现“不消耗次数”的效果,所以我们改用了 while。

  4. else 在循环中的作用和 if-else 完全不同,初学者容易混淆。只有在循环没有被 break 打断时,else 才会执行。


五、完整示例:模拟自动售货机找零

我们来一个贴近生活的综合例子:自动售货机里有 1元、5元、10元三种硬币,需要给顾客找零。输入要找的金额(整数,比如 18 元),程序尝试用尽量少的硬币(贪心算法)输出组合。这里我们用嵌套循环和 break 控制。

# 自动售货机找零:用最少硬币组合(1元 5元 10元)
def change_money(target):
    """找到 1元 5元 10元 的组合,使硬币数量最少"""
    found = False                   # 标志变量,是否找到解
    # 先尝试多用大面值硬币(贪心思想)
    for ten in range(target // 10, -1, -1):      # 10元硬币最多 target/10 个,从多到少
        for five in range(target // 5, -1, -1):  # 5元硬币最多 target/5 个
            one = target - (ten * 10 + five * 5)
            if one >= 0:                         # 剩余金额用 1元补足
                print(f"找零 {target} 元:10元 x {ten},5元 x {five},1元 x {one}")
                found = True
                break                           # 找到解就跳出内层循环
        if found:
            break                               # 跳出外层循环

change_money(18)   # 调用函数

输出:

找零 18 元:10元 x 1,5元 x 1,1元 x 3

这个程序利用了嵌套循环和标志变量,从大面值开始尝试,找到第一个解(硬币数最少)后立即跳出所有循环。


六、相关知识点指引

  • 要想在输入出错时重试,除了 try-except,还可以用 while True 循环加 break 实现“直到输入合法才继续”。
  • 如果你想深入学习异常处理,可以看《Python 异常捕获与调试》。
  • 关于循环嵌套的更多技巧,可以学习《二维列表与矩阵操作》。
  • 如果你想用循环控制玩更复杂的游戏,比如“猜数字”加上难度选择、记录历史猜测,可以看《函数与模块化设计》。

掌握这些循环控制工具后,你就能写出更智能、更稳健的程序了——比如自动检查班级作业、猜数字游戏不怕乱按、自动售货机聪明找零。快去试试吧!

例题精讲

1单选题

以下Python代码的输出是什么? for i in range(3): for j in range(3): if j == 1: break print(i, j)

A0 0\n1 0\n2 0
B0 0\n0 1\n1 0\n1 1\n2 0\n2 1
C0 0\n0 1\n0 2\n1 0\n1 1\n1 2\n2 0\n2 1\n2 2
D0 1\n1 1\n2 1
2判断题

在Python中,如果for循环正常结束(没有遇到break),则else子句中的代码会被执行。

3填空题
下面的代码使用嵌套循环和continue语句,统计0到9中所有不包含数字3的两位数的个数(十位从1-9,个位0-9)。请补全代码。
count = 0
for i in range(1, 10):
    if i == 3:
        ___
    for j in range(10):
        if j == 3:
            ___
        count += 1
print(count)
4单选题

以下代码的输出结果是什么? x = 0 while x < 5: x += 1 if x == 3: continue print(x, end=' ') else: print("完成")

A1 2 4 5 完成
B1 2 3 4 5 完成
C1 2 4 5
D1 2 3 4 5
5填空题
下面的代码使用for-else结构,在列表numbers中查找第一个大于10的数字,找到后打印该数字并退出循环;如果没找到,则打印"未找到"。请补全代码。
numbers = [3, 7, 9, 12, 5]
target = None
for num in numbers:
    if num > 10:
        target = num
        ___
else:
    print("未找到")
if target is not None:
    print("找到:", target)