第2章 2.3 while 循环与死循环
🎯 为什么要学这个?
你有没有遇到过这种情况——
「我要一直刷到这个视频点赞超过 1000!」
或者
「密码输入错误?没关系,我等下再试,反正无限次机会!」
这些场景,用编程语言来描述,就是「满足某个条件之前,一直重复做某件事」。
上一章我们学了 match-case,它让我们能像查字典一样快速匹配不同的模式。但它解决的是「一次性判断」的问题——
如果我想让程序一直干一件事,直到用户喊停呢?
比如:
- 做一个计时器,每秒更新一次,直到用户按 Ctrl+C
- 写一个密码验证器,输入错误就继续问,直到输入对为止
- 做一个行情监控器,每隔 5 秒刷新价格,直到用户退出
这种「满足条件就一直干」的场景,match-case 搞不定,普通的 if 也搞不定。
今天学的 while 循环,就是专门解决这个问题的。
学完本文,你将能独立写出:
- 自动重试的请求工具
- 带倒计时的互动程序
- 简单的游戏主循环
🧱 基础:while 循环是什么?
2.3.1 先看一个生活类比
想象你站在电梯门前,电梯门上写着:
「门保持关闭状态,直到有人按上楼按钮」
你盯着门,发现:
- 初始状态:门是关着的
- 判断条件:有人按按钮了吗?
- 如果没按:继续等着(循环体)
- 如果按了:门打开(退出循环)
这就是 while 循环的逻辑:
门是关着的
while 没人按按钮:
继续等着
门打开了
2.3.2 Python 语法就这么简单
# 初始化条件
count = 0
# 条件为 True 时,一直执行循环体
while count < 3:
print(f"第 {count + 1} 次:还在循环里...")
count = count + 1 # 别忘了改变条件,否则变成死循环
print("循环结束了!")
运行结果:
第 1 次:还在循环里...
第 2 次:还在循环里...
第 3 次:还在循环里...
循环结束了!
解释:
- count = 0:设置一个计数器,记录循环次数
- while count < 3::如果 count 小于 3,就进入循环
- count = count + 1:每次循环结束,把计数器加 1
注意! 如果你忘记写
count = count + 1,程序会永远停在循环里——这就是传说中的死循环。
2.3.3 计数器:循环的「进度条」
计数器就是循环的脚步——告诉程序「你跑了多远了,还剩多少」。
# 倒计时发射火箭
countdown = 5
while countdown > 0:
print(f"🚀 倒计时:{countdown} 秒")
countdown = countdown - 1
print("🔥 发射!")
运行结果:
🚀 倒计时:5 秒
🚀 倒计时:4 秒
🚀 倒计时:3 秒
🚀 倒计时:2 秒
🚀 倒计时:1 秒
🔥 发射!

2.3.4 break:提前退出循环
有时候我们不想等条件自己变假,而是想主动喊停。
# 猜数字游戏
secret_number = 7
guess = 0
while guess != secret_number:
guess = int(input("猜一个 1-10 的数字:"))
if guess == secret_number:
print("🎉 恭喜猜对了!")
break # 猜对了就退出循环
else:
print(f"不对,继续猜!")
print("游戏结束")
运行示例:
猜一个 1-10 的数字:3
不对,继续猜!
猜一个 1-10 的数字:7
🎉 恭喜猜对了!
游戏结束
解释:
- break:立即跳出循环,不再执行后面的代码
- 相当于循环里的「紧急出口」
2.3.5 continue:跳过本次循环
有时候遇到某种情况,我们想跳过这一次,直接进入下一次。
# 打印 1-10,但跳过所有偶数
num = 0
while num < 10:
num = num + 1
if num % 2 == 0: # 如果是偶数
continue # 跳过本次循环,直接下一次
print(num) # 只打印奇数
运行结果:
1
3
5
7
9
解释:
- continue:跳过循环体剩下的代码,直接进入下一次判断
- num % 2 == 0:判断是否为偶数(% 是取余数的意思)
2.3.6 while-else:循环正常结束才执行的代码
Python 的 while 循环还有个独特语法——else 块。
# 模拟用户登录
attempts = 3
password = "python123"
while attempts > 0:
guess = input("请输入密码:")
if guess == password:
print("✅ 登录成功!")
break
attempts = attempts - 1
print(f"❌ 密码错误,还剩 {attempts} 次机会")
else:
# 只有循环正常结束(没有被 break)才会执行这里
print("🚫 次数用完,账户已锁定")
运行示例:
请输入密码:123456
❌ 密码错误,还剩 2 次机会
请输入密码:python123
✅ 登录成功!
或者:
请输入密码:123456
❌ 密码错误,还剩 2 次机会
请输入密码:wrong
❌ 密码错误,还剩 1 次机会
请输入密码:again
🚫 次数用完,账户已锁定
解释:
- 如果循环被 break 退出,else 不执行
- 如果循环是自然条件变假而退出,else 执行

2.3.7 死循环:最常见的坑
死循环就是条件永远为 True,程序永远不会自己停下来。
# ❌ 错误示例:忘记改变条件
count = 0
while count < 3:
print("我会永远打印下去...") # count 永远是 0,永远不会 >= 3
正确写法:
# ✅ 正确示例:记得更新计数器
count = 0
while count < 3:
print(f"这是第 {count + 1} 次")
count = count + 1 # 每次循环都让 count 变大
print("循环正常结束")
什么时候可以用死循环?
有些场景确实需要死循环,比如服务器主循环:
# 服务器主循环:一直运行,直到被强制终止
while True:
connection = accept_connection()
handle_request(connection)
说白了:
while True就是「不管怎样都继续」,通常配合break使用。
🔥 实战:3 个递进项目
项目 1:自动刷新行情的小工具(5 分钟)
场景:你想监控一个价格,价格低于某个值就提醒你,否则每 5 秒刷新一次。
import time
# 模拟行情数据(实际可以用真实 API)
prices = [100, 98, 95, 97, 94, 93, 92, 90]
target_price = 91
index = 0
print(f"📊 监控价格:当前目标 ${target_price}")
print("按 Ctrl+C 可退出监控\n")
while True:
current_price = prices[index % len(prices)] # 循环使用列表
index = index + 1
print(f"[{index}] 当前价格:${current_price}", end="")
if current_price <= target_price:
print(" ✅ 价格到了!买入!")
break
else:
print(f" ❌ 还没到,继续监控...")
time.sleep(1) # 暂停 1 秒(实际可能是 5 秒)
预期输出:
📊 监控价格:当前目标 $91
按 Ctrl+C 可退出监控
[1] 当前价格:$100 ❌ 还没到,继续监控...
[2] 当前价格:$98 ❌ 还没到,继续监控...
[3] 当前价格:$95 ❌ 还没到,继续监控...
[4] 当前价格:$97 ❌ 还没到,继续监控...
[5] 当前价格:$94 ❌ 还没到,继续监控...
[6] 当前价格:$93 ❌ 还没到,继续监控...
[7] 当前价格:$92 ❌ 还没到,继续监控...
[8] 当前价格:$90 ✅ 价格到了!买入!
解释:用 while True 做主循环,配合 break 在条件满足时退出,用 time.sleep 控制刷新频率。
项目 2:CSV 数据清洗脚本(15 分钟)
场景:你有一份 CSV 文件,里面有用户的订单数据,但有些行是无效的(比如金额为负数或用户名为空),你需要过滤掉这些无效数据。
假设 orders.csv 内容:
username,amount,status
小明,150,completed
小红,0,pending
张三,200,completed
,100,completed
李四,-50,completed
王五,180,pending
# 读取 CSV 文件并清洗数据
with open('orders.csv', 'r', encoding='utf-8') as f:
lines = f.readlines()
# 跳过表头,从第二行开始处理
valid_count = 0
invalid_count = 0
invalid_reasons = []
index = 0
while index < len(lines):
line = lines[index].strip()
# 跳过空行
if not line:
index = index + 1
continue
# 跳过表头
if index == 0:
index = index + 1
continue
# 解析数据
parts = line.split(',')
username = parts[0].strip()
amount = parts[1].strip()
status = parts[2].strip()
# 验证数据
is_valid = True
reason = ""
if not username: # 用户名为空
is_valid = False
reason = "用户名为空"
try:
amount_num = float(amount)
if amount_num <= 0: # 金额必须大于 0
is_valid = False
reason = f"金额 {amount} 不合理"
except ValueError:
is_valid = False
reason = f"金额 {amount} 不是数字"
# 输出结果
if is_valid:
valid_count = valid_count + 1
print(f"✅ 有效订单:{username} - ${amount} - {status}")
else:
invalid_count = invalid_count + 1
invalid_reasons.append(reason)
print(f"❌ 无效数据(第 {index + 1} 行):{reason}")
index = index + 1
# 统计报告
print("\n" + "=" * 40)
print(f"📊 数据清洗完成")
print(f"✅ 有效订单:{valid_count} 条")
print(f"❌ 无效数据:{invalid_count} 条")
预期输出:
✅ 有效订单:小明 - $150 - completed
❌ 无效数据(第 2 行):金额 0 不合理
✅ 有效订单:张三 - $200 - completed
❌ 无效数据(第 4 行):用户名为空
❌ 无效数据(第 5 行):金额 -50 不合理
✅ 有效订单:王五 - $180 - pending
========================================
📊 数据清洗完成
✅ 有效订单:3 条
❌ 无效数据:3 条
解释:用 while 循环逐行处理 CSV 文件,配合 if 条件判断数据是否有效,统计有效和无效的数量。
项目 3:待办事项管理器(15 分钟)
场景:做一个命令行的待办事项管理工具,用户可以:
1. 添加待办事项
2. 查看所有待办
3. 标记完成
4. 删除待办
5. 退出程序
# 待办事项管理器
todos = []
print("📝 欢迎使用待办事项管理器")
print("=" * 30)
while True:
print("\n请选择操作:")
print("1. 添加待办")
print("2. 查看待办列表")
print("3. 标记完成")
print("4. 删除待办")
print("5. 退出程序")
choice = input("\n请输入选项(1-5):").strip()
if choice == "1":
# 添加待办
task = input("请输入待办事项:").strip()
if task:
todos.append({"task": task, "done": False})
print(f"✅ 已添加:「{task}」")
else:
print("❌ 待办事项不能为空")
elif choice == "2":
# 查看列表
if not todos:
print("📭 暂无待办事项")
else:
print(f"\n📋 待办列表(共 {len(todos)} 项):")
index = 1
while index <= len(todos):
item = todos[index - 1]
status = "✅" if item["done"] else "⬜"
done_mark = " [已完成]" if item["done"] else ""
print(f" {index}. {status} {item['task']}{done_mark}")
index = index + 1
elif choice == "3":
# 标记完成
if not todos:
print("📭 暂无待办事项")
else:
try:
num = int(input("请输入要完成的序号:"))
if 1 <= num <= len(todos):
todos[num - 1]["done"] = True
print(f"✅ 已标记完成:「{todos[num - 1]['task']}」")
else:
print("❌ 序号超出范围")
except ValueError:
print("❌ 请输入数字")
elif choice == "4":
# 删除待办
if not todos:
print("📭 暂无待办事项")
else:
try:
num = int(input("请输入要删除的序号:"))
if 1 <= num <= len(todos):
removed = todos.pop(num - 1)
print(f"🗑️ 已删除:「{removed['task']}」")
else:
print("❌ 序号超出范围")
except ValueError:
print("❌ 请输入数字")
elif choice == "5":
# 退出
print("\n👋 感谢使用,待办事项管理器已退出!")
if todos:
remaining = sum(1 for t in todos if not t["done"])
print(f"📊 你还有 {remaining} 项待办未完成")
break
else:
print("❌ 无效选项,请输入 1-5")
print("\n程序结束")
预期输出(部分演示):
📝 欢迎使用待办事项管理器
===============================
请选择操作:
1. 添加待办
2. 查看待办列表
3. 标记完成
4. 删除待办
5. 退出程序
请输入选项(1-5):1
请输入待办事项:买牛奶
✅ 已添加:「买牛奶」
请输入选项(1-5):1
请输入待办事项:写周报
✅ 已添加:「写周报」
请输入选项(1-5):2
📋 待办列表(共 2 项):
1. ⬜ 买牛奶
2. ⬜ 写周报
请输入选项(1-5):3
请输入要完成的序号:1
✅ 已标记完成:「买牛奶」
请输入选项(1-5):2
📋 待办列表(共 2 项):
1. ✅ 买牛奶 [已完成]
2. ⬜ 写周报
请输入选项(1-5):5
👋 感谢使用,待办事项管理器已退出!
📊 你还有 1 项待办未完成
程序结束
解释:用 while True 做主循环,配合 if-elif-else 处理不同选项,用 break 退出程序。
💪 进阶:常见坑 + 性能小贴士
坑 1:忘记更新计数器,变成死循环
# ❌ 错误:count 永远是 0
count = 0
while count < 3:
print("永远打印")
# 程序卡住
# ✅ 正确:每次循环更新计数器
count = 0
while count < 3:
print(f"第 {count + 1} 次")
count = count + 1
坑 2:while 条件写错,导致多执行一次或少执行一次
# ❌ 错误:会打印 0-4,而不是 0-3
count = 0
while count <= 3:
print(count)
count = count + 1
# 输出:0, 1, 2, 3, 4
# ✅ 正确:严格小于才进入循环
count = 0
while count < 3:
print(count)
count = count + 1
# 输出:0, 1, 2
坑 3:break 和 continue 混用时搞不清逻辑
# 打印 1-10,跳过 5,但打印到 6 就停
num = 0
while num < 10:
num = num + 1
if num == 5:
continue # 跳过 5,直接下一次
if num == 7:
break # 遇到 7 就退出
print(num)
# 输出:1, 2, 3, 4, 6
坑 4:在 while 循环里修改列表时出错
# ❌ 错误:边遍历边删除,可能漏掉元素
fruits = ["苹果", "香蕉", "樱桃", "香蕉", "葡萄"]
i = 0
while i < len(fruits):
if fruits[i] == "香蕉":
fruits.pop(i) # 删除后列表变短,但 i 没变
else:
i = i + 1
# 可能出问题
# ✅ 正确:创建新列表
fruits = ["苹果", "香蕉", "樱桃", "香蕉", "葡萄"]
fruits = [f for f in fruits if f != "香蕉"]
# 或者:
while "香蕉" in fruits:
fruits.remove("香蕉")
坑 5:while-else 的 else 容易被忽略
# 找第一个大于 5 的数,找到就 break
numbers = [1, 3, 4, 2, 6, 8]
index = 0
while index < len(numbers):
if numbers[index] > 5:
print(f"找到了:{numbers[index]}")
found = True
break
index = index + 1
else:
# 如果循环正常结束(没被 break),才会执行这里
found = False
print("没找到大于 5 的数")
print(f"最终结果:found = {found}")
性能小贴士:减少循环内的函数调用
# ❌ 低效:每次循环都调用 len()
items = list(range(100))
i = 0
while i < len(items): # 每次都要计算 len()
print(items[i])
i = i + 1
# ✅ 高效:先把长度存起来
items = list(range(100))
length = len(items) # 只计算一次
i = 0
while i < length:
print(items[i])
i = i + 1
调试技巧:用 print 追踪变量值
# 在关键位置打印变量值,帮助理解循环执行过程
count = 0
while count < 3:
print(f"[DEBUG] count = {count}, 条件 = {count < 3}")
count = count + 1
print(f"[DEBUG] 执行后 count = {count}")
print(f"[DEBUG] 循环结束,count = {count}")
输出:
[DEBUG] count = 0, 条件 = True
[DEBUG] 执行后 count = 1
[DEBUG] count = 1, 条件 = True
[DEBUG] 执行后 count = 2
[DEBUG] count = 2, 条件 = True
[DEBUG] 执行后 count = 3
[DEBUG] 循环结束,count = 3
✏️ 练习题
练习 1(1 分钟):抄改计数器
# 把下面的循环改成倒序输出 5 到 1
count = 1
while count <= 5:
print(count)
count = count + 1
- 输入:直接运行
- 预期输出:
5 4 3 2 1(每行一个) - 提示:改
while条件和count的更新方式
练习 2(2 分钟):加 if 判断
在练习 1 的基础上,只打印奇数。
- 输入:直接运行
- 预期输出:
5 3 1(每行一个) - 提示:用
%取余判断奇偶,不符合就continue
练习 3(3 分钟):处理新数据
用项目 2 的方法,创建一个 students.csv,包含 name,score,grade 三列,处理逻辑:只保留 score >= 60 的学生,并在最后统计通过率。
- 输入:创建 CSV 文件并运行代码
- 预期输出:显示通过的学生列表和通过率百分比
- 提示:把项目 2 的
amount改成score,判断条件改成>= 60
练习 4(3 分钟):串接项目 2 和项目 3
把项目 2 的「数据清洗」结果,用项目 3 的「待办列表」方式展示:清洗出哪些有效订单,把它们加入待办清单。
- 输入:沿用
orders.csv数据 - 预期输出:把有效订单作为待办事项显示
- 提示:把清洗后的
valid_count条数据转换成待办列表格式
练习 5(3 分钟):分析死循环
下面代码会卡住,说明原因并修复:
num = 10
while num > 0:
print(num)
num = num + 1 # 这里写错了
- 输入:运行代码
- 预期输出:程序会一直打印 > 10 的数字,不会停止
- 提示:
num + 1应该是num - 1
作业:做一个「数字猜谜游戏」
需求描述:
做一个猜数字游戏,程序随机生成 1-100 的整数,玩家有 5 次猜测机会,每次提示「太大了」或「太小了」,猜对或用完次数游戏结束。
功能点:
1. 程序随机生成答案
2. 玩家输入猜测,系统反馈
3. 显示剩余次数
4. 游戏结束时显示结果(猜对/猜错)
加分项:
1. 记录猜测历史(每次猜了什么)
2. 猜错后提示距离答案还差多少
验收标准:
- 能跑起来
- 输入 1-100 的数字有正确反馈
- 5 次用完自动退出
- 代码有注释
提交方式: 评论区贴代码或 GitHub 链接
📚 总结
本文学了 3 个核心点:
1. while 循环的语法:初始化 → 条件判断 → 循环体 → 更新计数器
2. break 提前退出、continue 跳过本次、else 正常结束才执行
3. 死循环的成因:忘记更新计数器或条件永远为 True
延伸学习资源:
- 官方文档:while 语句 — 权威语法说明
- 书籍:《Python编程:从入门到实践》第 9 章 — 循环的更多例子
- 视频:B 站「小甲鱼 Python 教程」第 38 讲 — 生动讲解 while 循环
你在什么时候用过 while 循环?
我先说一个我的——以前写爬虫的时候,用 while True 配合 break 做「自动重试」:请求失败就继续请求,直到成功或者重试次数用完。
你在 XX 场景用过这个吗?评论区聊聊,老粉优先回复!

评论(0)