3.4 while 循环
while 循环是 Python 中另一种核心循环结构,与 for 循环的遍历已知集合定位不同,while 更适合在不确定循环次数、需要根据条件决定是否继续的场景中使用。本节从基本语法入手,逐步讲解条件判断、无限循环、标志变量、计数器、输入验证、嵌套结构等内容,并讨论 while 与 for 的适用场景区分,帮助你建立对 while 循环的完整认识。
3.4.1 while 循环的基本语法
while 循环的写法是 while 条件表达式:,后面跟缩进的循环体。每次循环开始前,解释器先求值条件表达式,为真则执行循环体一次,为假则跳出循环。循环体中通常要包含改变条件的语句,否则循环无法结束。
count = 0
while count < 3:
print("count =", count)
count += 1
# count = 0
# count = 1
# count = 2这个例子中 count += 1 是让条件最终变为假的关键语句。如果漏掉这一行,count < 3 永远为真,循环将无限执行下去。写 while 循环时,养成"先想清楚什么时候停"的习惯能避免大量死循环问题。while 语句末尾的冒号不可省略,它标志循环体的开始,缩进规则与 if、for 一致。
3.4.2 条件表达式的布尔值判断
while 的条件表达式会被隐式转换为布尔值。Python 中数字 0、空容器(空字符串、空列表、空字典等)、None、False 都被视为假,其他值视为真。这一规则让 while 能直接用容器或数字作为条件,写法简洁。
queue = ["task1", "task2", "task3"]
while queue:
task = queue.pop(0)
print("处理", task)
# 处理 task1
# 处理 task2
# 处理 task3这里 while queue 在列表非空时为真,列表清空后自动停止。这种写法等价于 while len(queue) > 0,但更符合 Python 风格。使用时要注意确保循环体确实会让容器逐渐变空,否则同样会陷入死循环。布尔转换的规则与 if 语句完全一致,可以参考第 3 章条件判断部分的内容。
3.4.3 无限循环的写法
while True: 是常见的无限循环写法,条件恒为真,循环不会自然结束。这种结构通常配合 break 语句在满足特定条件时主动跳出,适用于循环次数事先无法确定的场景,比如持续读取用户输入直到收到退出指令。
while True:
cmd = input("请输入命令(quit 退出):")
if cmd == "quit":
break
print("执行:", cmd)关于 break
break 语句会立即终止当前所在的最内层循环,把控制权交还给循环之后的代码。在 while True 结构中,break 是退出循环的唯一常规出口,写循环体时要确保 break 的触发条件最终能够满足,否则程序会卡在循环里无法退出。
无限循环的危险在于一旦忘记写 break 或 break 条件永远不成立,程序就会卡死。在调试阶段可以加一个最大迭代次数的保险计数器,超过阈值就强制退出,便于定位逻辑问题。生产代码中使用 while True 时,最好在循环体开头检查是否超时或收到外部终止信号,避免长期运行的服务出现无法停止的情况。
3.4.4 使用标志变量控制 while 循环退出
当退出条件比较复杂,分散在循环体的多个分支时,可以用一个布尔变量集中管理退出状态,这种变量通常叫标志变量(flag)。循环条件直接检查 flag,循环体内部根据业务逻辑把 flag 设为 False 来请求退出。
running = True
while running:
action = input("请输入动作(stop 停止):")
if action == "stop":
running = False
else:
print("执行动作:", action)
print("程序结束")标志变量的好处是把"是否继续"这一状态显式化,循环体各处都可以通过修改它来表达退出意图,逻辑比散落的多个 break 更清晰。在事件循环、游戏主循环等结构中,这种模式非常常见。需要注意设置 flag 为 False 后,当前这一轮循环体仍会执行完毕,退出发生在下一轮条件判断时,如果有清理工作要立即完成,应该在设 flag 的同时直接处理。
3.4.5 while 循环中的计数器变量初始化、递增、递减
while 循环常配合计数器变量使用,构成"初始化、判断、更新"三段式结构。计数器在循环开始前初始化,在条件中参与判断,在循环体中递增或递减。这三步缺一不可,否则循环行为会偏离预期。
# 递增计数器:从 1 累加到 5
total = 0
i = 1 # 初始化
while i <= 5: # 判断
total += i
i += 1 # 递增
print(total) # 15
# 递减计数器:从 5 倒数到 1
n = 5
while n > 0:
print(n, end=" ")
n -= 1 # 递减
# 5 4 3 2 1计数器变量在循环结束后仍然存在,保留的是让条件变假的那个临界值。例如上面的 i 循环结束后 i 等于 6,n 循环结束后 n 等于 0。这一点在调试时可以利用,但也容易让人误用,使用时要清楚变量的最终状态。浮点数计数器要特别小心,由于浮点累加误差,用 += 0.1 这类步长可能让循环多跑或少跑一次,涉及浮点时建议改用整数计数器配合除法。
3.4.6 用户输入验证循环
while 循环非常适合做用户输入验证,在用户输入合法之前反复提示,直到拿到有效数据为止。这种结构把"获取输入"和"验证输入"放在一个循环里,逻辑紧凑。
while True:
age_str = input("请输入年龄(0-120):")
if age_str.isdigit():
age = int(age_str)
if 0 <= age <= 120:
print("有效年龄:", age)
break
print("输入无效,请重新输入。")这个例子嵌套了两层验证:先检查是否为纯数字,再检查数值范围。任何一层失败都会重新提示。输入验证循环的关键是提示信息要清晰,让用户知道哪里出了问题以及如何修正,否则用户会在死循环里反复试错。对于更复杂的输入格式,可以结合 try/except 捕获转换异常,错误处理在第 6 章详细展开。
3.4.7 文件读取循环
while 循环也可以用于按行读取文件,每次读取一行,读到文件末尾(返回空字符串或特定标记)时停止。这种模式在处理大文件时比较常见,因为它不需要一次性把整个文件加载到内存。
关于文件读取
文件操作涉及打开、读取、关闭等细节,会在第 6 章详细讲解。本节只列出 while 在文件读取中的角色,具体写法留到文件章节展开。现代 Python 更推荐直接用 for line in file: 的写法按行迭代文件对象,它由解释器保证正确关闭和边界处理,写法也更简洁。
按行 while 读取的思路是反复调用读取方法,直到返回值为空字符串为止。这种结构在旧代码中比较常见,新代码大多改用 for 迭代。理解 while 在其中的作用有助于阅读遗留代码,也便于在需要精细控制读取节奏时(比如每读一行做一次额外判断)灵活调整。
3.4.8 while-else 结构
Python 的 while 支持一个可选的 else 子句,当循环正常结束(条件变假)而非被 break 中断时执行。这一结构的典型用途是在搜索类循环中区分"找到了"和"找遍了也没找到"两种情况。
n = 2
while n < 100:
if n == 50:
print("找到了 50")
break
n += 1
else:
print("没找到 50")while-else 的语义初学者容易困惑,else 在这里的意思更接近"循环完毕后做的事"。如果循环被 break 跳出,else 不会执行;如果条件自然变假退出,else 才执行。这一结构相对小众,详细介绍和更多示例放在第 5 章控制流进阶部分统一展开,本节仅作了解,遇到时能识别其含义即可。
3.4.9 嵌套 while 循环
while 循环可以嵌套,外层 while 每执行一次,内层 while 完整跑一遍直到其条件变假。嵌套 while 常用于多维遍历或需要多重条件配合的场景,比如打印乘法表、遍历二维网格。
i = 1
while i <= 3:
j = 1
while j <= 3:
print(f"{i}*{j}={i*j}", end=" ")
j += 1
print()
i += 1
# 1*1=1 1*2=2 1*3=3
# 2*1=2 2*2=4 2*3=6
# 3*1=3 3*2=6 3*3=9嵌套 while 要特别注意内层计数器在内层循环开始前重新初始化,否则第二次外层循环时内层条件已经为假,内层体一次都不执行。这是嵌套循环常见的 bug 来源,调试时先检查内层变量的重置位置。break 在嵌套结构中只跳出最内层循环,如果需要一次跳出多层,可以用标志变量配合外层条件判断,或者把内层循环封装成函数用 return 退出。
3.4.10 while 循环与 for 循环的适用场景区分
while 和 for 都能实现循环,但适用场景有侧重。for 循环适合在已知迭代对象或迭代次数的情况下使用,比如遍历列表、按范围重复若干次,写法简洁且不容易死循环。while 循环适合在循环次数不确定、需要根据运行时条件决定是否继续的场景,比如等待用户输入、轮询状态、读取数据流直到结束。
# for:已知范围,求 1 到 10 的平方
for i in range(1, 11):
print(i * i, end=" ")
# 1 4 9 16 25 36 49 64 81 100
# while:条件驱动,不断除以 2 直到结果小于 1
x = 100
steps = 0
while x >= 1:
x = x / 2
steps += 1
print("步数:", steps)
# 步数: 7实际开发中能确定次数就优先用 for,它的边界更明确、出错概率更低。只有当终止条件是动态的、无法预先转换为"迭代 N 次"时,才考虑用 while。两者也可以组合使用,外层 while 控制整体流程,内层 for 处理每一轮的批量操作。选择哪种循环的核心标准是看终止条件能否在循环开始前表达为一个明确的迭代范围,能则用 for,不能则用 while。
练习题
第 1 题:写出下列代码的输出结果
阅读下面这段 while 循环代码,在不运行的情况下写出它的输出。
n = 10
total = 0
while n > 0:
total += n
n -= 2
print(total)参考答案
输出 30。n 依次取 10、8、6、4、2,累加结果为 10 + 8 + 6 + 4 + 2 = 30。当 n 变为 0 时条件 n > 0 不成立,循环结束。
n -= 2 是让条件最终变假的关键语句,如果漏掉这行会陷入死循环。
第 2 题:用 while 循环实现倒数计数
请用 while 循环从 5 倒数到 1,每个数字单独一行打印,最后打印"发射"。
参考答案
count = 5
while count > 0:
print(count)
count -= 1
print("发射")输出:
5
4
3
2
1
发射计数器 count 在循环前初始化为 5,每轮循环结束后递减 1,当 count 等于 0 时条件 count > 0 变假,循环退出。
第 3 题:编写输入验证循环
请用 while True 配合 break 编写一段代码,提示用户输入一个 1 到 100 之间的整数。输入合法时打印该数字并退出循环,输入不合法时提示重新输入。可以用一个固定变量代替 input() 来模拟测试。
参考答案
# 模拟用户输入序列
inputs = ["abc", "150", "-5", "42"]
idx = 0
while True:
user_input = inputs[idx]
idx += 1
print("输入:", user_input)
if user_input.isdigit():
num = int(user_input)
if 1 <= num <= 100:
print("有效数字:", num)
break
print("输入无效,请输入 1 到 100 之间的整数")输出:
输入: abc
输入无效,请输入 1 到 100 之间的整数
输入: 150
输入无效,请输入 1 到 100 之间的整数
输入: -5
输入无效,请输入 1 到 100 之间的整数
输入: 42
有效数字: 42实际使用时把 inputs[idx] 替换为 input("请输入数字:") 即可。while True 配合 break 是输入验证循环的标准写法,循环次数事先无法确定。
第 4 题:项目练习题(命令行任务管理器)
命令行任务管理器需要持续接收用户命令直到输入 quit。请用 while True 编写主循环骨架,读取命令并通过 break 退出。可以用一个固定列表代替 input() 模拟多个命令。
参考答案
commands = ["add", "list", "unknown", "quit"]
idx = 0
while True:
cmd = commands[idx]
idx += 1
print("收到命令:", cmd)
if cmd == "quit":
print("退出程序")
break
print("处理命令:", cmd)输出:
收到命令: add
处理命令: add
收到命令: list
处理命令: list
收到命令: unknown
处理命令: unknown
收到命令: quit
退出程序while True 配合 break 是交互式命令循环的典型结构。循环次数事先不确定,由用户输入的 quit 命令触发退出。
常见错误
错误 1 · 程序卡死不输出,CPU 占用满载
原因:while 循环条件永远为真,循环体中没有改变条件的语句,形成死循环。这是 while 循环常见的错误。
解决:确认循环体中包含让条件最终变假的语句(如计数器递增或容器弹出元素)。调试时可加一个最大迭代次数的保险计数器。
错误 2 · continue 跳过计数器更新导致死循环
原因:在 while 循环中,continue 语句之后的代码不会执行。如果计数器更新语句写在 continue 之后,被跳过后循环条件永远成立。
解决:把计数器更新语句放在 continue 之前,或确保每个分支都有更新逻辑。
错误 3 · 浮点数计数器导致循环多跑或少跑一次
原因:浮点数累加存在精度误差,例如 0.1 + 0.1 + 0.1 的结果不精确等于 0.3。用浮点数作为计数器,条件判断可能在错误的时机成立。
解决:改用整数计数器配合除法,或使用 math.isclose() 做浮点数比较。