Python: 分支循环实战
学了这么多理论知识,是时候动手做几个像样的项目了。这节是纯实战课,我们将用前面学过的 if 条件判断、for 循环、while 循环、break、continue 等知识,一步步搭建四个完整的程序。
每个项目我们都会先分析思路,再写出代码,最后讨论可能的改进方向。
1. 实战 1:猜数字游戏(增强版)
第 08 课我们写了一个基础的猜数字游戏,现在来给它升级:加入难度选择、猜测次数限制、以及"再来一局"功能。
(1) 需求分析
1. 玩家选择难度:简单(1-50,无限次)、普通(1-100,10次)、困难(1-200,7次)
2. 系统随机生成目标数字
3. 玩家每次猜测后,提示"大了"或"小了",并显示剩余次数
4. 猜中或次数用尽后,询问"是否再来一局"
5. 输入 q 退出游戏
(2) 完整代码(⭐⭐⭐)
▶ 示例:猜数字游戏
import random
print("=" * 30)
print("🎯 猜数字游戏(增强版)")
print("=" * 30)
while True: # 外层循环:控制"再来一局"
# 选择难度
print("\n请选择难度:")
print("1. 简单(1~50,无限次数)")
print("2. 普通(1~100,10次)")
print("3. 困难(1~200,7次)")
choice = input("请输入 1/2/3:")
if choice == "1":
max_num = 50
max_attempts = float("inf") # 无限次
elif choice == "2":
max_num = 100
max_attempts = 10
elif choice == "3":
max_num = 200
max_attempts = 7
else:
print("无效选择,默认普通难度")
max_num = 100
max_attempts = 10
# 生成目标数字
target = random.randint(1, max_num)
attempts = 0
print(f"\n已生成 1~{max_num} 之间的数字,开始猜吧!")
# 内层循环:游戏主逻辑
while True:
# 检查次数是否用尽
if attempts >= max_attempts:
print(f"\n😵 次数用尽!正确答案是 {target}")
break
# 获取玩家输入
guess_str = input(f"还剩 {max_attempts - attempts} 次,请输入:")
if guess_str.lower() == "q":
print("退出游戏。")
# 注意:这里 break 只跳出内层循环,需要特殊处理
max_attempts = -1 # 用标记通知外层循环
break
# 验证输入是否为有效数字
if not guess_str.isdigit():
print("请输入有效的数字!")
continue
guess = int(guess_str)
attempts += 1
# 判断大小
if guess < target:
print("小了,再大一点!")
elif guess > target:
print("大了,再小一点!")
else:
print(f"\n🎉 恭喜你猜对了!就是 {target}!")
print(f"你用了 {attempts} 次猜中。")
break
# 检查是否要退出整个程序
if max_attempts == -1: # 玩家输入了 q
break
# 询问是否再来一局
again = input("\n再来一局?(y/n):")
if again.lower() != "y":
print("感谢游玩,再见!")
break
max_attempts = -1 这个标记值来解决"内层 break 后外层也要 break"的问题。你也可以用更优雅的方式——把游戏逻辑封装成函数,用 return 一次性退出。
2. 实战 2:九九乘法表(多种样式)
第 08 课我们打印了标准九九乘法表。一个优秀的程序员,应该能灵活控制循环结构,输出任意样式。
(1) 样式 1:标准下三角(⭐⭐)
▶ 示例:标准下三角乘法表
print("=== 标准下三角 ===")
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}×{i}={i*j}", end="\t")
print()
输出:
=== 标准下三角 ===
(2) 样式 2:完整矩形(⭐⭐)
▶ 示例:完整矩形乘法表
print("=== 完整矩形 ===")
for i in range(1, 10):
for j in range(1, 10):
print(f"{j}×{i}={i*j}", end="\t")
print()
输出:
=== 完整矩形 ===
(3) 样式 3:上三角(⭐⭐⭐)
▶ 示例:上三角乘法表
print("=== 上三角 ===")
for i in range(1, 10):
# 先打印空白对齐
for k in range(1, i):
print(end="\t\t")
# 再打印乘法算式
for j in range(i, 10):
print(f"{i}×{j}={i*j}", end="\t")
print()
输出效果:
=== 上三角 ===
1×1=1 1×2=2 1×3=3 … 1×9=9
2×2=4 2×3=6 … 2×9=18
3×3=9 … 3×9=27
…
9×9=81
(i-1) × 2 个制表符的空位。这就用到了两个内层循环的技巧:第一个内层循环打空白,第二个内层循环打印算式。
3. 实战 3:简易计算器(增强版)
在第 08 课的作业中我们写了一个基础计算器,现在来做增强版:支持连续运算、保存历史记录。
(1) 需求分析
1. 启动后显示当前结果为 0
2. 用户输入格式: 运算符 数字,例如 "+ 5"
3. 支持的运算符: + - * / ** // % clear exit
4. clear 重置结果为 0
5. exit 退出程序
6. 每次运算后显示当前结果和历史记录
(2) 完整代码(⭐⭐⭐)
▶ 示例:增强版计算器
print("=" * 40)
print("🧮 增强版计算器")
print("输入格式:运算符 数字,例如:+ 5")
print("支持:+ - * / ** // %")
print("特殊指令:clear(重置) exit(退出)")
print("=" * 40)
result = 0.0
history = [] # 保存运算历史
while True:
# 显示当前结果
print(f"\n当前结果:{result}")
# 获取用户输入
cmd = input(">>> ").strip()
# 处理特殊指令
if cmd.lower() == "exit":
print("感谢使用!")
break
if cmd.lower() == "clear":
result = 0.0
history.clear()
print("已重置为 0")
continue
# 解析普通运算指令
parts = cmd.split()
if len(parts) != 2:
print("格式错误!请输入:运算符 数字")
continue
op, num_str = parts
# 验证数字有效性
if not num_str.replace(".", "").isdigit() or num_str.count(".") > 1:
print("无效的数字!")
continue
num = float(num_str)
# 执行运算
old_result = result
if op == "+":
result += num
elif op == "-":
result -= num
elif op == "*":
result *= num
elif op == "/":
if num == 0:
print("错误:除数不能为 0!")
continue
result /= num
elif op == "**":
result **= num
elif op == "//":
if num == 0:
print("错误:除数不能为 0!")
continue
result //= num
elif op == "%":
if num == 0:
print("错误:除数不能为 0!")
continue
result %= num
else:
print(f"无效运算符:{op}")
continue
# 记录历史
history.append(f"{old_result} {op} {num} = {result}")
# 显示结果
print(f"= {result}")
# 显示最近 3 条历史(如果有的话)
if len(history) >= 1:
print("--- 最近记录 ---")
for item in history[-3:]:
print(f" {item}")
运行示例:
>>> + 10
= 10.0
--- 最近记录 ---
0.0 + 10.0 = 10.0
>>> * 3
= 30.0
--- 最近记录 ---
0.0 + 10.0 = 10.0
10.0 * 3.0 = 30.0
>>> / 0
错误:除数不能为 0!
>>> clear
已重置为 0
while True 保持程序持续运行,用 if-elif-else 处理各种输入情况,用 continue 跳过无效输入,用 break 正常退出。
4. 实战 4:质数查找器
让用户输入一个范围,输出该范围内所有的质数,并统计个数。
(1) 需求分析
1. 用户输入起始值和结束值
2. 程序输出该范围内所有的质数
3. 每行显示 10 个,整齐排列
4. 最后显示质数的总个数
(2) 完整代码(⭐⭐⭐)
▶ 示例:质数查找器
print("🔢 质数查找器")
print("输入一个范围,我将找出其中的所有质数。")
# 获取范围
start_str = "2" # 演示用固定值
end_str = "50" # 演示用固定值
# 验证输入
if not (start_str.isdigit() and end_str.isdigit()):
print("请输入有效的正整数!")
else:
start = int(start_str)
end = int(end_str)
if start < 2:
start = 2
print("起始值已调整为 2(质数从 2 开始)")
if start > end:
print("起始值不能大于结束值!")
else:
primes = [] # 存放找到的质数
# 遍历范围内的每个数
for num in range(start, end + 1):
# 判断 num 是否为质数
is_prime = True
for i in range(2, int(num ** 0.5) + 1):
if num % i == 0:
is_prime = False
break
if is_prime:
primes.append(num)
# 输出结果
print(f"\n在 {start} ~ {end} 之间,共找到 {len(primes)} 个质数:")
for i, prime in enumerate(primes, 1):
print(f"{prime:5d}", end="")
if i % 10 == 0: # 每 10 个换行
print()
print() # 最后换行
运行示例:
起始值(≥2):50
结束值:200
在 50 ~ 200 之间,共找到 34 个质数:
53 59 61 67 71 73 79 83 89 97
101 103 107 109 113 127 131 137 139 149
151 157 163 167 173 179 181 191 193 197
199
num-1,只需要除到 √num 就可以了。因为如果 num 有一个大于 √num 的因子,那必然有一个小于 √num 的因子成对存在。这种优化在处理大范围(比如 10 万以上)时效果非常明显。
5. 实战 5:BMI 健康指数 + 密码强度检测
这个实战把算术运算、比较运算、逻辑运算、条件判断、字符串方法全部串起来,解决两个生活中常见的问题。
(1) 第一部分:BMI 健康指数(⭐⭐)
BMI(Body Mass Index,身体质量指数)是国际上常用的衡量人体胖瘦程度的指标。公式很简单:
BMI = 体重(kg) ÷ 身高(m)²
▶ 示例:BMI 健康指数
# BMI 健康指数计算器
# 输入数据
weight = 68
height = 1.75
# 计算 BMI
bmi = weight / (height ** 2)
print("=== BMI 健康指数 ===")
print(f"您的体重:{weight} kg")
print(f"您的身高:{height} m")
print(f"您的BMI:{bmi:.1f}")
# 用链式比较和 if-elif 判断等级
if bmi < 18.5:
print("判定:偏瘦")
elif 18.5 <= bmi < 24:
print("判定:正常 👍")
elif 24 <= bmi < 28:
print("判定:偏胖 ⚠️")
else:
print("判定:肥胖 🔴")
运行结果:
=== BMI 健康指数 ===
您的体重:68 kg
您的身高:1.75 m
您的BMI:22.2
判定:正常 👍
18.5 <= bmi < 24,是不是比写成 bmi >= 18.5 and bmi < 24 清爽很多?
(2) 第二部分:密码强度检测(⭐⭐⭐)
写个程序来判断用户设置的密码安不安全。一个密码的强度取决于它的长度和包含的字符类型。
▶ 示例:密码强度检测
# 密码强度检测器
password = "Py3#thon"
# 统计密码的各种特征
length = len(password) # 长度
has_digit = any(c.isdigit() for c in password) # 是否包含数字
has_letter = any(c.isalpha() for c in password) # 是否包含字母
has_special = not password.isalnum() # 是否有特殊字符
print("=== 密码强度检测 ===")
print(f"密码:{password}")
print(f"长度:{length}")
print(f"包含数字:{has_digit}")
print(f"包含字母:{has_letter}")
print(f"包含特殊字符:{has_special}")
# 用逻辑运算符组合条件来判断强度
if length < 6:
strength = "弱"
elif length >= 10 and has_digit and has_letter and has_special:
strength = "强"
elif length >= 8 and has_digit and has_letter:
strength = "中"
else:
strength = "弱"
print(f"密码强度:{strength}")
运行结果:
=== 密码强度检测 ===
密码:Py3#thon
长度:8
包含数字:True
包含字母:True
包含特殊字符:True
密码强度:中
len() 获取字符串长度,isdigit() 判断是否为数字,isalpha() 判断是否为字母,isalnum() 判断是否只包含字母和数字(如果包含特殊字符就返回 False,用 not 取反就是 "包含特殊字符")。这些方法在后面的字符串课会系统学习。
6. 🐛 分支循环常见错误
写代码难免出错,特别是刚学循环的时候。下面几个是最典型的"坑",每个初学者都会踩到。
(1) 错误 1:死循环——忘了更新条件变量
# ❌ 错误写法
n = 1
while n <= 10:
print(n)
# 忘了 n += 1 —— 永远跑不完
# ✅ 正确写法
n = 1
while n <= 10:
print(n)
n += 1
(2) 错误 2:= 和 == 弄混
# ❌ 错误写法
if score = 100: # 这是赋值,不是比较!
print("满分!")
# ✅ 正确写法
if score == 100:
print("满分!")
(3) 错误 3:循环内修改正在遍历的列表
# ❌ 错误写法 —— 遍历时删除元素会导致"跳过"
numbers = [1, 2, 3, 4, 5]
for num in numbers:
if num % 2 == 0:
numbers.remove(num)
print(numbers) # 可能不是你想的结果
# ✅ 正确写法 —— 创建新列表
numbers = [1, 2, 3, 4, 5]
odd_numbers = [num for num in numbers if num % 2 != 0]
print(odd_numbers)
(4) 错误 4:range() 的结束值理解错
# ❌ 以为 range(5) 会输出 1 2 3 4 5
for i in range(5):
print(i) # 实际输出: 0 1 2 3 4
# ✅ 正确写法
for i in range(1, 6):
print(i) # 输出: 1 2 3 4 5
7. 常见应用场景
| 场景 | 使用的循环/分支技巧 | 说明 |
|---|---|---|
| 数据处理(过滤、清洗) | for + continue |
跳过无效数据 |
| 用户交互菜单 | while True + break |
反复显示菜单直到选择退出 |
| 分页加载 | while + 条件判断 |
直到没有更多数据 |
| 搜索/查找 | for + break + else |
找到即停,找不到则执行 else |
| 批量文件处理 | for + 嵌套逻辑 |
遍历目录中的每个文件 |
| 游戏主循环 | while True + 事件处理 |
持续渲染和响应输入 |
❓ 常见问题
False?② 循环体有没有修改条件相关变量?③ while True 有没有对应的 break?在代码里加 print() 输出关键变量值,是调试死循环最有效的方法。range() 和列表直接遍历,哪个效率高?range() 返回惰性序列,不一次性生成所有数字,range(1000000) 几乎不占内存;list(range(1000000)) 会占用大量内存。循环次数大时直接用 range() 更省内存。📖 小节
- 猜数字增强版:外层循环控制"再来一局",内层控制"猜数字",用
while True+break管理多层循环的退出 - 九九乘法表多样式:通过控制内层循环的
range()范围,可以输出下三角、上三角、矩形等不同样式 - 计算器增强版:
continue跳过无效输入,列表保存历史记录,split()解析用户输入 - 质数查找器:优化判断到
√num可大幅提升效率,enumerate(primes, 1)实现带序号输出 - 调试技巧:死循环检查三要素、
=与==区分、不要在遍历时修改列表
📝 作业
⭐ 第一题:水仙花数
"水仙花数"是指一个三位数,其各位数字的立方和等于该数本身。例如:153 = 1³ + 5³ + 3³。
请用 for 循环找出所有的水仙花数(共 4 个)。
提示:用 range(100, 1000) 遍历所有三位数,用 // 和 % 分解百位、十位、个位。
⭐⭐ 第二题:打印菱形
接收用户输入一个奇数 n,在控制台输出一个由 * 组成的菱形。
示例(n=5):
*
***
*****
***
*
提示:菱形由上下两部分组成。上半部分 i 从 1 到 n//2 + 1,空格数递减,星号数递增。
⭐⭐⭐ 第三题:学生成绩管理系统
编写一个程序,实现以下功能:
1. 输入学生成绩(输入 q 结束输入)
2. 计算总分、平均分、最高分、最低分
3. 统计各分数段人数:90-100(优秀)、80-89(良好)、70-79(中等)、60-69(及格)、<60(不及格)
4. 输出成绩排名(从高到低)
要求:
- 使用
while True循环收集成绩 - 使用列表存储成绩
- 用
for循环统计分数段 - 用
sorted(..., reverse=True)排序
参考输出:
请输入学生成绩(输入 q 结束):
第 1 位学生成绩:85
第 2 位学生成绩:92
第 3 位学生成绩:67
第 4 位学生成绩:78
第 5 位学生成绩:55
第 6 位学生成绩:q
===== 成绩统计 =====
总人数:5
总分:377.0
平均分:75.4
最高分:92.0
最低分:55.0
===== 分数段分布 =====
优秀(90-100):1 人
良好(80-89):1 人
中等(70-79):1 人
及格(60-69):1 人
不及格(<60):1 人
===== 成绩排名 =====
92 85 78 67 55
这个项目综合运用了循环、列表、排序、统计等知识,完成它你就真正掌握了 Python 的基础控制流。