循环嵌套
困难0循环嵌套:就像日历里有月份和日期
有时候一个循环不够,需要在一个循环里面再放一个循环,这就是循环嵌套。简单说,就是一个循环的“身体”里,又写了一个循环。比如我们看日历:外面是大循环——月份从1到12;里面是小循环——每个月的天数从1号到28或30或31号。用循环嵌套可以很方便地处理这种“两层结构”的问题。
生活中还有很多这样的例子:
- 课程表:外面是星期几(周一至周五),里面是每天的课节(第1节、第2节……)
- 食堂排队:外面是年级(一年级、二年级……),里面是每个年级的同学依次打饭
- 游戏地图:外面是行(从上到下),里面是列(从左到右),每个格子放一个角色
什么是循环嵌套?
循环嵌套就是在一个循环的代码块里,再写一个完整的循环。外层循环每执行一次,内层循环就要从头到尾完整地执行一遍。就像这样:
for 外层变量 in 外层范围: # 外层循环
# 外层循环的代码
for 内层变量 in 内层范围: # 内层循环(嵌套)
# 内层循环的代码
# 外层循环还可能有些代码(比如换行)
注意:内层循环必须完全在外层循环的内部,并且缩进要正确。缩进错了,内层循环就可能跑到外面去了,结果就不是嵌套了。
为什么需要循环嵌套?
因为有时候我们遇到的不是“一条直线”上的重复,而是“表格”或“网格”式的重复。比如:
- 要打印一个 5 行 5 列的星星方阵,需要重复行(外层循环),每行又要重复打印列(内层循环)
- 要遍历一个二维列表(如考试成绩表),需要先遍历行,再遍历每行里的列
- 要画出各种图形(三角形、菱形),每行的星星数量不同,需要用内层循环控制数量
生活中的例子:打印一个小星星三角形
想象你要用星星拼出一个直角三角形:
*
**
***
****
*****
第1行1个星,第2行2个星……第5行5个星。这就可以用循环嵌套:外层循环控制行数(1到5),内层循环控制每行要打印的星星个数(等于当前行号)。
rows = 5 # 总行数
for i in range(1, rows + 1): # 外层循环 i 从1到5,代表行号
for j in range(i): # 内层循环 j 从0到i-1,共i次,打印i个星
print('*', end='') # end='' 表示不换行,连续打印星
print() # 每行结束后换行
运行结果:
*
**
***
****
*****
如果把这个三角形反过来(倒三角),只需要让外层循环从大到小,或者调整内层循环的范围。试试把 range(1, rows+1) 改成 range(rows, 0, -1) 看看效果。
最经典的例子:九九乘法表
上面已经提到过九九乘法表,我们再来仔细分析一遍它的工作过程。
for i in range(1, 10): # 外层循环 i 从1到9,代表行号(也是第一个乘数)
for j in range(1, i + 1): # 内层循环 j 从1到i,每行的列数等于当前行号
product = i * j # 计算结果
print(f"{j}x{i}={product}", end="\t") # 打印算式,用制表符分隔
print() # 每一行结束后换行
一步步拆解(以 i=3 为例):
- 外层 i=3,进入内层:
- j=1: 打印
1x3=3,不换行 - j=2: 打印
2x3=6,不换行 - j=3: 打印
3x3=9,不换行
- j=1: 打印
- 内层结束,执行
print()换行,然后继续外层 i=4
这样,每行打印的算式个数正好等于行号,结果就是等腰直角三角形的乘法表。
注意:这里内层循环的范围 range(1, i+1) 是动态变化的,因为每行的列数不同,外层变量 i 控制着内层循环的次数。
循环嵌套还可以干什么?
1. 处理二维列表
假设有一个成绩表,每行是一个同学,每列是各科成绩:
# 成绩表:行代表同学,列代表 [语文, 数学, 英语]
scores = [
[90, 85, 88], # 小明
[78, 92, 80], # 小红
[95, 89, 91] # 小刚
]
for row in scores: # 外层循环:遍历每个同学(每一行)
total = 0 # 这个同学的总分
for score in row: # 内层循环:遍历该同学的各科成绩
total += score
print(f"总分: {total}")
2. 画更复杂的图案
比如打印空心正方形:
n = 5 # 边长
for i in range(n): # 外层循环:行
for j in range(n): # 内层循环:列
if i == 0 or i == n-1 or j == 0 or j == n-1: # 在第一行、最后一行、第一列、最后一列打印*
print('*', end=' ')
else:
print(' ', end=' ') # 其他位置打印空格
print() # 每行结束换行
新手容易犯的错误
错误1:缩进错误——内层循环跑到了外面
for i in range(3):
print("外层", i)
for j in range(2): # 这个缩进不对!它和上面for是平级的,不是嵌套
print("内层", j)
这样只会先执行外层循环3次,再执行内层循环2次,不是嵌套效果。正确写法是内层循环缩进到外层循环内部。
错误2:忘记重置内层变量或计数器
有时候我们需要在内层循环开始前重置某个变量,比如累加总分:
for row in scores:
total = 0 # 重要:每处理一个新行,先清零
for score in row:
total += score
print(total)
如果 total = 0 放在了外层循环外面,那么它只会清零一次,之后每个同学的总分会累加前面的结果,就错了。
错误3:内外层循环变量名混用
for i in range(5):
for i in range(3): # 内外层用了同一个变量名 i
print(i)
这样内层循环会改变外层 i 的值,导致外层循环失控。建议内层用不同的变量名,比如 j 或 k。
错误4:无限循环(当用while时)
i = 1
while i <= 3:
j = 1
while j <= 3:
print(i, j)
j += 1 # 别忘了更新j,否则内层无限循环
i += 1 # 别忘了更新i
用 while 嵌套时一定要小心更新循环变量的语句,否则容易死循环。
完整可运行示例:打印数字金字塔
下面是一个完整的程序,它打印一个数字金字塔(每行显示从1到行号的数字),并且加了注释:
# 打印数字金字塔,共6行
rows = 6 # 总行数
for i in range(1, rows + 1): # 外层循环:行号 i 从1到6
# 1) 打印空格,让金字塔居中
for space in range(rows - i): # 内层循环1:打印空格
print(' ', end=' ') # 每行前面空 (rows-i) 个空格
# 2) 打印数字:从1递增到i
for num in range(1, i + 1): # 内层循环2:打印递增数字
print(num, end=' ') # 不换行,空格分隔
# 3) 打印数字:从i-1递减到1
for num in range(i - 1, 0, -1): # 内层循环3:打印递减数字
print(num, end=' ')
print() # 换行,准备下一行
运行结果(金字塔形状):
1
1 2 1
1 2 3 2 1
1 2 3 4 3 2 1
1 2 3 4 5 4 3 2 1
1 2 3 4 5 6 5 4 3 2 1
相关知识点指引
- for 循环:循环嵌套的基础,要熟练掌握
range()的用法(起始、结束、步长) - while 循环:也可以用 while 实现嵌套,但要小心无限循环
- 列表和二维列表:循环嵌套经常用来遍历二维列表,比如矩阵、成绩表
- 字符串格式化:如
f"{j}x{i}={product}",让输出更整齐 - break 和 continue:可以在循环嵌套中使用,但要注意它们只作用于当前所在的循环(最内层)
尝试自己动手改一改上面的例子:把数字金字塔改成字母金字塔,或者用循环嵌套画一个棋盘格。多练几次,你就会发现循环嵌套其实就像玩俄罗斯套娃——一层一层,整整齐齐。
例题精讲
执行以下代码后,变量 s 的值是多少? s = 0 for i in range(3): for j in range(i+1): s += 1 print(s)
执行以下代码会输出 10 个星号(*)。 for i in range(5): for j in range(2): print('*', end='')
以下代码使用循环嵌套输出一个 3 行 4 列的矩形,每行由4个星号组成。请填写缺失的代码。
for i in range(3):
for j in range(___):
print('*', end='')
print()关于以下代码,说法正确的是? count = 0 for i in range(1, 6): for j in range(1, i): count += 1 print(count)
以下代码用循环嵌套打印一个直角三角形(第 i 行有 i 个星号,i从1开始)。请补充内层循环的 range 参数。
for i in range(1, 6):
for j in range(___):
print('*', end='')
print()