Python循环结构入门:for和while的5个经典简单例题
本文系统讲解Python中的for和while循环结构,通过执行流程图对比两种循环的底层机制与选型依据,并结合1到100求和、九九乘法表、数字位数统计、列表过滤和猜数字游戏5个经典简单例题,帮助初学者快速掌握循环控制与避坑要点。
for 和 while 两种语句构成:前者依托迭代协议在已知区间或数据序列中顺次取值,后者基于布尔条件的真假控制执行流。本文直入代码与执行原理,通过 5 个涵盖累加、排版、数字拆解、序列过滤及交互控制的经典例题,帮助初学者建立扎实的循环思维与避坑直觉。
一、循环的核心机制:for 与 while 怎么选?
初学 Python 时,最常见的困惑是“面对一个问题,究竟该写 for 还是 while”。回答这个问题的关键在于明确循环边界的确定方式。
for 循环本质上是一个迭代器遍历器。每次执行时,它会自动从可迭代对象(如 range() 范围序列、列表、元组、字符串或字典)中按顺序提取下一个元素,并将元素赋值给临时变量,直到序列中的内容全部取完后平稳退出。因为其循环次数或遍历范围在循环启动前就已经确定,所以代码逻辑紧凑,天然不存在计数器忘记自增而引发的死循环风险。
while 循环则是一个条件判定器。它在每次循环体执行前,对给定的布尔表达式进行求值。只要表达式为 True,代码块就会持续执行;一旦表达式变为 False,循环立即终止。这种机制特别适用于循环终止条件无法预先计算、需要等待外部输入、或者依靠运算逐步逼近收敛的场景。
| 对比维度 | for 循环 | while 循环 |
|---|---|---|
| 控制机制 | 遍历迭代对象(序列、容器、range) |
依据条件表达式的真假(True / False) |
| 计数器推进 | 由 Python 底层迭代机制自动推进 | 需在循环体内手动编写步进更新语句 |
| 死循环风险 | 极低(序列元素有限时必定终止) | 较高(若条件无法收敛至 False 则陷入死循环) |
| 适用场景 | 固定次数计次、遍历容器列表、成对解包 | 用户交互等待、游戏主循环、状态机轮询、数值收敛 |
二、例题一:计算 1 到 100 的累加和(累加器模型)
计算 1 + 2 + 3 + ... + 100 是所有编程语言中最经典的循环例题。它的核心解题思维是累加器模型(Accumulator Pattern):在进入循环前先定义一个总和变量置为 0,然后让循环变量依次产生 1 到 100 的整数,逐一累加进总和变量中。
1. 使用 for 循环实现
在 Python 中,生成连续数字序列使用内置的 range() 函数。需要特别注意:range(start, stop) 生成的是左闭右开区间 [start, stop),即包含 start 但不包含 stop。要覆盖 1 到 100,参数必须设为 range(1, 101)。
# 1. 在循环外部初始化累加器
total_sum = 0
# 2. 遍历 1 到 100 的整数
for i in range(1, 101):
total_sum += i # 等价于 total_sum = total_sum + i
# 3. 循环结束后输出结果
print("1到100的累加和为:", total_sum)
2. 使用 while 循环实现
如果改用 while 循环,开发者需要自行管理计数器变量 i 的生命周期:先在循环前赋初始值 1,设置终止条件 i <= 100,并且在每轮累加后显式执行 i += 1。
total_sum = 0
i = 1 # 显式初始化计数器
while i <= 100:
total_sum += i
i += 1 # 关键:步进自增,推进循环状态
print("while循环计算结果为:", total_sum)
total_sum = 0 写在 for 或 while 的循环体内部。若置于内部,每一轮循环都会将总和重新清零,最终只会输出最后一项的值。所有用于收集最终成果的变量,必须在循环前声明。
三、例题二:打印九九乘法表(嵌套循环与格式化输出)
九九乘法表考验的是双层循环(Nested Loops)的组织能力以及控制台的格式排版技巧。双层循环常用于处理二维空间问题(如表格、矩阵、图像像素),外层循环负责推进纵向的“行”,内层循环负责打印横向的“列”。
1. 逻辑推导与代码实现
观察乘法表的下三角特征:第 1 行只打印 1 项(1×1),第 2 行打印 2 项(1×2, 2×2),依此类推,第 i 行需要打印 i 项(列数 j 从 1 遍历到 i)。因此,内层循环的 range 上界必须动态依赖外层变量 i,即 range(1, i + 1)。
# 外层循环:控制行号 i 从 1 到 9
for i in range(1, 10):
# 内层循环:控制列号 j 从 1 到 i
for j in range(1, i + 1):
# end="\t" 表示打印完不换行,而是输出制表符对齐
print(f"{j}*{i}={i * j}", end="\t")
# 内层一整行打印完毕后,输出一个空 print() 实现换行
print()
print()函数默认在末尾追加换行符。通过传入参数end=" ",可以让本行的多个乘法项排在同一行,并利用制表符保持列间距规整。- 内层
for j执行结束后,紧接着执行缩进与外层对其的print(),利用其默认行为打出回车换行,准备进入下一行。
四、例题三:统计正整数的位数(while 状态逼近模型)
虽然通过将数字转为字符串 len(str(num)) 可以直接获得长度,但使用纯数学方式拆解整数是理解计算机算法中数值收敛与状态递减的绝佳途径。本题要求:输入一个正整数,计算它一共有多少位。
1. 为什么更适合 while 循环?
面对一个任意输入的整数(例如 985211),我们无法直接得知循环具体要跑多少圈,因此无法构造 for i in range(...)。但我们知道其数学收敛规律:任意正整数每整除一次 10(// 10),就会剥离掉最末尾的一位数字。当数字衰减至 0 时,剥离的次数即为该整数的总位数。
def count_digits(num: int) -> int:
# 特殊情况处理:数字 0 也是 1 位数
if num == 0:
return 1
# 兼容负数输入,取绝对值
n = abs(num)
digits = 0
# 只要 n 还大于 0,就说明还有高位未被剥离
while n > 0:
n //= 10 # 整数整除,抹去个位
digits += 1 # 计数器递增 1 位
return digits
# 验证测试用例
test_number = 985211
result = count_digits(test_number)
print(f"数字 {test_number} 的位数为: {result} 位")
n = 985211 时:
第 1 轮后 n = 98521, digits = 1;
第 2 轮后 n = 9852, digits = 2;
第 5 轮后 n = 9, digits = 5;
第 6 轮后 n = 0, digits = 6。
此时条件 n > 0 判定为 False,循环安全退出。
五、例题四:列表数据筛选与统计(for in 序列遍历模型)
在实际业务开发中,最普遍的操作是从一组集合数据中找出符合条件的条目并进行统计。本题任务:给定一组学生考试成绩列表,统计及格人数(>= 60 分)以及及格学生的总平均分。
1. 代码实现与容器遍历
Python 的 for ... in 语法可以直接遍历列表中的每个数据元素,开发者完全无需维护传统语言中类似 i = 0; i < len(list); i++ 的下标索引变量,这有效杜绝了越界访问错误(IndexError)。
scores = [78, 56, 89, 92, 45, 60, 83, 38, 95, 71]
pass_count = 0 # 及格人数累加器
pass_total_score = 0 # 及格总分累加器
for score in scores:
# 条件过滤:只关心大于等于 60 分的成绩
if score >= 60:
pass_count += 1
pass_total_score += score
# 防止列表无及格人员导致的除零错误
if pass_count > 0:
average_pass = pass_total_score / pass_count
print(f"及格人数: {pass_count} 人")
print(f"及格学生平均分: {average_pass:.2f} 分")
else:
print("本批次无及格学生")
for score in scores 表达的是“针对每一项分数”,意图比 for i in range(len(scores)) 更加直观清晰,执行效率也更高。如果遍历时同时需要下标和值,可以使用 Python 内置的 enumerate(scores)。
六、例题五:猜数字游戏(循环控制与交互模型)
猜数字游戏是掌握 while True 无限循环以及流程干预关键字 break、continue 的典型场景。程序预设或随机生成一个目标数字,玩家反复输入竞猜值,程序根据大小给予反馈,直到猜中时主动跳出循环。
1. 流程控制关键字的作用
break:立即强行跳出当前所在的整层循环,不再执行循环体内后续代码,也不再进入下一轮循环。continue:立即结束本轮循环,跳过循环体内剩余的语句,直接进入下一次循环条件的判定。
2. 模拟运行代码示例
import random
def guess_number_game(target=42, mock_inputs=[25, 70, 42]):
print("【猜数字游戏启动】目标范围 1 到 100")
attempts = 0
input_index = 0
# 开启持续等待的轮询循环
while True:
# 这里使用模拟输入流,实际应用中替换为 int(input("请输入数字: "))
if input_index < len(mock_inputs):
guess = mock_inputs[input_index]
input_index += 1
else:
break
attempts += 1
print(f"第 {attempts} 次尝试,输入为: {guess}")
# 1. 范围校验与跳过 (continue 演示)
if guess < 1 or guess > 100:
print("输入超出 1~100 有效范围,请重新输入!")
continue # 跳过后续比较,直接开始下一轮
# 2. 命中目标退出 (break 演示)
if guess == target:
print(f"恭喜猜中!正确答案就是 {target},共用了 {attempts} 次。")
break # 任务完成,彻底终止循环
elif guess < target:
print("太小了,再大一点!")
else:
print("太大了,再小一点!")
# 运行测试
guess_number_game(target=42, mock_inputs=[25, 70, 42])
七、Python 循环结构全景总结与避坑清单
通过上述 5 个经典例题,我们可以抽象出 Python 循环处理任务的核心认知结构:先分析终止特征(已知总量用 for,未知事件用 while),再匹配数据骨架(累加聚合、矩阵空间、状态逼近或条件过滤),最后利用 break / continue 进行细粒度控制。
编写循环时必须自查的 4 项法则
- while 步进自增检查:只要写下了
while 变量 < 边界:,紧接着第一件事就应该在循环体底部写上变量 += 步长。很多死循环导致的程序卡死、内存暴涨,都是由于漏写了自增语句或自增逻辑被分支跳过造成的。 - range 区间差一问题(Off-by-one Error):切记
range(1, n)只会产生到n - 1。若要包含n本身,必须写成range(1, n + 1)。 - 累加与结果变量的生命周期:所有用于跨轮次汇总的容器(如
total、count、result_list)必须置于循环体外部进行初始化。若写在循环体内,每一轮都会被重新初始化,破坏了状态的保留。 - 缩进与控制层级:Python 完全依赖缩进来区分代码归属。循环结束后的处理代码(如
print(total)、返回语句return)必须退回与for/while同级的缩进,否则会被作为循环体的一部分重复执行,甚至引发逻辑提前中断。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









