1 循环的本质 —— 把重复劳动交给程序
是什么?为什么学?
循环(loop)是让程序反复执行同一段代码的语法结构。写代码时,80% 的「重复」工作都能用循环解决:打印 100 次、累加 100 个数、处理 100 个文件……不会循环,代码又臭又长;学会循环,代码量直接减少一个数量级。如果让你打印 100 遍「加油」,你不会真的写 100 行 print——循环就是让程序「自动重复」的语法。
底层原理
计算机的 CPU 本质上是「一条一条执行指令」的机器,它内部有一个「指令指针」,记录下一条该执行哪条指令。循环的原理就藏在这里:循环体执行完后,指令指针不是继续往下走,而是跳回循环开头,再次判断条件 / 取下一个元素;直到条件不成立或元素取完,才跳出循环继续往后执行。
生活类比
循环像一台复读机:按一下「播放」,它就把同一句话翻来覆去地念。复读机的「次数旋钮」定好念几遍,循环里的 range() 也定好执行几次——把「重复劳动」交给机器自动完成,这正是循环存在的意义。
注意事项总结
1 循环版 vs 手写版:
# 手写版:打印 3 遍要写 3 行
print("加油")
print("加油")
print("加油")
# 循环版:想打印 100 遍也只是改一个数字
for i in range(3):
print("加油")
运行结果(两者一致):
加油
加油
加油
for i in range(3): 做了两件事——range(3) 生成 0、1、2 三个数字;for i in 让变量 i 依次取这三个值,每取一个值就执行一次缩进的代码,取完 3 个值循环自动结束。行首的缩进(4 个空格)告诉 Python「哪些代码属于循环体」。
2 循环变量 i 的值是怎么变化的:
for i in range(4):
print("第", i, "次循环")
运行结果:
第 0 次循环
第 1 次循环
第 2 次循环
第 3 次循环
注意从 0 开始!每轮循环开始前,Python 自动把下一个值放进变量 i,不需要我们手动去改 i,这是 for 循环和 while 循环最不一样的地方。
3 循环 + 变量 = 批量计算:
for i in range(1, 6):
print(i, "的平方是", i * i)
运行结果:
1 的平方是 1
2 的平方是 4
3 的平方是 9
4 的平方是 16
5 的平方是 25
循环体里不仅能打印,还能做任何计算——这就是循环「批量处理」的威力。
易错点
- 错误写法:
for i in range(3): print(i)挤在一行 → 问题:虽然能运行,但循环体一多行就容易乱,养成坏习惯 → 正确写法:循环体统一换行 + 缩进 4 个空格。 - 错误写法:循环体不缩进,下一行直接顶格写 → 问题:报
IndentationError,Python 分不清哪些代码属于循环 → 正确写法:循环体内每一行都比 for 行多缩进 4 个空格。 - 错误写法:以为
range(3)是 1、2、3 → 问题:实际是 0、1、2,循环体会执行 3 次 → 正确写法:数「循环几次」只看 range 里的数字:range(n)= n 次。
记忆口诀:缩进体内反复念;range 定次数,变量每次换新值。
2 range() 的秘密 —— 含头不含尾与步长
是什么?为什么学?
range() 是 Python 内置的「数字序列生成器」,用来告诉 for 循环「循环几次、从几开始、隔几个取一个」。它是循环次数控制的核心工具,几乎每个循环都会用到它。
底层原理
range() 不会把一串数字全部生成出来存放在内存里(循环 1 亿次会撑爆内存),而是「惰性生成」:每次需要下一个数时,按公式(起始值 + 当前次数 × 步长)现场算出来,所以循环多少次都只占固定内存。「含头不含尾」是 Python 在 range、切片、区间里统一采用的约定,好处是:range(n) 恰好生成 n 个数,与「下标从 0 开始」完美配合。
生活类比
range 像电影院里的座位号:从第几排开始、到第几排结束、隔几个座位坐一人,都写得很清楚。座位号永远从 0 排开始数(含头),到结束号那排不坐人(不含尾)——记住这个约定,range 就不会数错。
注意事项总结
1 range 的三种形态:
print(list(range(5))) # 0 到 4:一个参数 = 生成几个数
print(list(range(2, 6))) # 2 到 5:两个参数 = 从哪开始,到哪结束(不含尾)
print(list(range(1, 10, 3))) # 1、4、7:三个参数 = 再加步长
运行结果:
[0, 1, 2, 3, 4]
[2, 3, 4, 5]
[1, 4, 7]
list(range(...)) 是把 range 生成的序列「展开」成列表显示出来(直接 print(range(5)) 只会显示 range(0, 5) 这个对象本身)。range(1, 10, 3) 从 1 开始每次加 3:1、4、7、10——但 10 不含(含头不含尾),所以结果是 1、4、7。
2 步长为负 = 倒着数:
for i in range(5, 0, -1):
print("倒计时:", i)
print("发射!")
运行结果:
倒计时: 5
倒计时: 4
倒计时: 3
倒计时: 2
倒计时: 1
发射!
range(5, 0, -1) 从 5 开始,每次减 1,直到 0 之前(不含 0)为止。步长是负数时,起始值必须大于结束值,否则生成的是空序列。
3 range 与字符串下标配合:
word = "Python"
for i in range(len(word)):
print("第", i, "个字符是:", word[i])
运行结果:
第 0 个字符是: P
第 1 个字符是: y
第 2 个字符是: t
第 3 个字符是: h
第 4 个字符是: o
第 5 个字符是: n
len(word) 得到字符串长度 6;range(6) 生成 0~5;word[i] 用下标取出第 i 个字符。这种「range + 下标」的组合,在需要「知道当前是第几个」时非常有用(Day 6 遍历列表时还会见到)。
易错点
- 错误写法:
range(5)以为生成 15 → 问题:实际生成 04,不含 5 → 正确写法:想要 1~5 写range(1, 6)。 - 错误写法:
range(1, 5)以为有 5 个数 → 问题:只有 4 个数(1、2、3、4) → 正确写法:个数 = 结束值 – 开始值。 - 错误写法:
range(10, 0, 2)想从 10 数到 0 → 问题:生成的是空序列!步长为正要求开始 < 结束 → 正确写法:倒着数要写range(10, 0, -2)。 - 错误写法:
for i in range("abc")→ 问题:报TypeError,range 只接受整数 → 正确写法:数字用 range;字符串直接for ch in "abc"。
记忆口诀:含头不含尾,起步看开始;步长定增减,倒序写负数。
3 while 循环 —— 条件驱动与死循环防范
是什么?为什么学?
while 循环在「条件为真」期间一直执行,适合不知道要循环多少次的场景:比如让用户反复输入直到输入正确、程序一直运行直到用户选择退出。它是写「交互式程序」的基石。
底层原理
while 的执行流程是:① 判断条件(一个布尔表达式,结果为 True 或 False)→ ② 为真则执行循环体 → ③ 执行完跳回第 ① 步重新判断 → ④ 条件为假,跳出循环。关键点:循环体里必须有能影响条件的代码(比如计数变量加 1、重新读一次输入),否则条件永远为真,程序就陷入死循环。
生活类比
while 像商场门口的门卫:只认一条规则——「进店条件」成立就放人进去,进去一趟出来再检查一次,条件不成立就关门不放了。如果你忘了告诉门卫「什么时候该关门」(循环体里没有让条件变假的代码),他就会一直放人,永远不停——这就是死循环。
注意事项总结
1 while 实现「累加输入的数字,直到输入 0 结束」:
total = 0
num = int(input("请输入一个数字(输入 0 结束):"))
while num != 0:
total = total + num
num = int(input("请输入一个数字(输入 0 结束):"))
print("总和是:", total)
运行结果(示例输入 5、7、0):
请输入一个数字(输入 0 结束):5
请输入一个数字(输入 0 结束):7
请输入一个数字(输入 0 结束):0
总和是: 12
让条件变假的代码(重新 input)写在循环体里,如果漏写,num 永远不变,就会死循环。
2 while 计算阶乘:
n = 5
result = 1
i = 1
while i <= n:
result = result * i
i = i + 1
print("5 的阶乘 =", result)
运行结果:
5 的阶乘 = 120
result 初始为 1(乘法的「起点」);i 从 1 数到 5,每轮把 i 乘进 result,然后 i = i + 1。这里的 i = i + 1 就是「让条件变假」的关键代码,漏掉就是死循环。
3 死循环长什么样(错误示范,千万不要运行):
# count = 1
# while count <= 5:
# print("我停不下来了")
# 上面这段没有 count = count + 1,条件永远为真,程序永远不结束。
# 如果不小心运行了死循环程序,在终端按 Ctrl + C 强制终止。
易错点
- 错误写法:循环体里忘了更新计数变量(
i = i + 1) → 问题:条件永远为真,程序卡死(死循环) → 正确写法:检查循环体里有没有「让条件变假」的代码。 - 错误写法:条件方向写反(
while i > 5想数到 5) → 问题:一开始就是假,循环体一次都不执行 → 正确写法:想「从 1 数到 5」写while i <= 5。 - 错误写法:
while True:忘记写 break → 问题:无限循环,程序永远不退出 → 正确写法:用while True:时循环体内必须有break出口。 - 错误写法:循环体缩进错误(顶格写) → 问题:报
IndentationError,或循环体根本没被执行 → 正确写法:循环体必须在while行的下一层缩进。
记忆口诀:条件为真一直跑,体内改条件,别让它死循环。
4 break / continue / 循环的 else —— 控制循环的节奏
是什么?为什么学?
break 是「急刹车」:立即结束整个循环;continue 是「跳过这一轮」:结束本次循环体的执行,直接进入下一次。再配合循环的 else(循环自然结束才执行),可以写出清晰高效的「搜索 / 过滤 / 校验」逻辑。
底层原理
程序里所有「重复」都由跳转指令实现:break 翻译成机器指令就是「无条件跳转到循环结束之后的位置」;continue 是「跳回循环开头(再次判断条件或取下一个元素)」。循环的 else 块是一个「确认信号」:只有循环没有被 break 打断、自然结束时才执行,相当于「整轮都没有被中断」。
生活类比
开车上班的路上:break 是急刹车——遇到事故立刻把车停住,剩下的路程全都不走了;continue 是跳过这一站——这一站不下车,车继续往前开;循环的 else 则是「跑完全程才发的一张’到站确认卡’」——中途急刹车(break)了,卡就发不出来。
注意事项总结
1 break——找到目标立刻停(搜索场景):
numbers = [3, 8, 15, 22, 31] # 列表 Day 6 细讲,今天先会用
for n in numbers:
if n > 20:
print("找到第一个大于 20 的数:", n)
break
print("检查:", n)
运行结果:
检查: 3
检查: 8
检查: 15
找到第一个大于 20 的数: 22
当 n = 22 时条件成立,break 立刻跳出循环——后面的 31 不会再被检查。这是「搜索到第一个满足条件的就停」的标准写法。
2 continue——跳过不需要处理的(过滤场景):
for i in range(1, 7):
if i == 3:
continue # 3 我们不处理,直接跳过本次
print("处理:", i)
运行结果:
处理: 1
处理: 2
处理: 4
处理: 5
处理: 6
continue 让程序跳过本次循环的剩余代码,直接进入下一次循环。注意 continue 只跳过「这一次」,不是结束整个循环。
3 for-else——循环正常结束才执行 else(校验场景):
for i in range(2, 10):
if i % 7 == 0:
print("找到了能被 7 整除的数:", i)
break
else:
print("2 到 9 之间没有能被 7 整除的数")
运行结果:
找到了能被 7 整除的数: 7
这里的 else 与 for 对齐(缩进层级相同),不是和 if 对齐。找到了 7,执行 print 后 break 打断循环,else 不执行。如果把 range(2, 10) 改成 range(2, 7),找不到 7 的倍数,循环自然结束,就会打印 else 的内容——你可以亲手试试。
易错点
- 错误写法:
continue写在 print 的后面 → 问题:先打印了不该打印的内容,continue 没起作用 → 正确写法:continue 必须写在「想跳过的代码」之前。 - 错误写法:
break写在 if 外面 → 问题:第一次循环就直接退出,循环形同虚设 → 正确写法:break 必须写在条件判断(if)里面。 - 错误写法:把
else和if对齐 → 问题:else 变成 if 的分支,逻辑完全变了 → 正确写法:else 必须和 for / while 同缩进。 - 错误写法:想用 break 跳出多层嵌套循环 → 问题:只能跳出 break 所在的那一层,外层还在跑 → 正确写法:用「标志变量」记录状态,或把逻辑写成函数(Day 8)。
记忆口诀:break 一响就收工,continue 跳过下一轮;else 等循环自然完,被 break 打断它不干。
5 循环嵌套 —— 循环里套循环
是什么?为什么学?
循环里面再写一个循环,就是循环嵌套。外层循环每执行一次,内层循环就要完整执行一遍。常用于生成表格、图形、乘法口诀表这类「行 × 列」的结构。
注意事项总结
1 外层控制行,内层控制列:
for i in range(1, 4): # 外层:3 行
for j in range(1, 4): # 内层:每行 3 列
print(i, j, end=" | ")
print() # 每行结束换行
运行结果:
1 1 | 1 2 | 1 3 |
2 1 | 2 2 | 2 3 |
3 1 | 3 2 | 3 3 |
2 用 * 画一个三角形:
for i in range(1, 6):
print("*" * i)
运行结果:
*
**
***
****
*****
执行顺序:外层取 i=1,内层把 j=1,2,3 全部跑完;然后外层取 i=2,内层再全部跑一遍……所以内层总共执行的次数 = 外层次数 × 内层次数。
易错点
- 错误写法:忘记内层循环也要缩进 → 问题:报
IndentationError,或内层循环根本没生效 → 正确写法:内层循环体比外层再缩进一层。 - 错误写法:
print()换行写在循环外面 → 问题:所有内容挤在一行,看不出「行 × 列」结构 → 正确写法:内层循环结束后用print()换行。
记忆口诀:外层走一步,内层跑一圈;总次数相乘,别忘缩进深。
6 动手实践:累加器 + 乘法口诀表
任务 1:累加器 —— 把 1 到 100 的所有整数加起来(答案是 5050),分别用 for 和 while 各写一遍。
# 累加器:用 for 实现
total = 0
for i in range(1, 101):
total = total + i
print("1+2+...+100 =", total)
# 输出:1+2+...+100 = 5050
# 累加器:用 while 实现
total = 0
i = 1
while i <= 100:
total = total + i
i = i + 1
print("while 版本结果:", total)
# 输出:while 版本结果: 5050
任务 2:乘法口诀表 —— 用循环嵌套打印九九乘法口诀表,格式为 1x1=1 这种。
# 九九乘法口诀表
for i in range(1, 10): # 外层:乘数 1~9
for j in range(1, i + 1): # 内层:只到 i,避免重复(1x2 和 2x1 只留一个)
print(f"{j}x{i}={i * j}", end=" ")
print() # 每行结束换行
运行结果:
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81
想一想:为什么内层用 range(1, i + 1)?试着改成 range(1, 10) 运行看看,体会「避免重复」的设计思路。f"{j}x{i}={i * j}" 是 f-string,花括号里的变量会被替换成它的值。
今日总结
循环是什么:让程序自动重复执行同一段代码,缩进的代码块就是循环体
循环的本质:CPU 的指令指针执行完循环体后「跳回」循环开头,直到条件不成立或元素取完
for 适合「知道次数 / 遍历集合」,while 适合「条件控制、次数未知」
range() 含头不含尾:range(n) 生成 0~n-1,步长为负可以倒着数
while 循环体里必须有让条件变假的代码,防止死循环;Ctrl + C 可强制终止
break 结束整个循环,continue 跳过本次,循环的 else 只在自然结束时执行
循环嵌套:外层每执行一次,内层完整执行一遍,总次数 = 外层次数 × 内层次数
完成累加器(结果 5050)和乘法口诀表
| 报错 | 原因 | 修复 |
|---|---|---|
SyntaxError: expected ':' | for / while 行尾忘了写冒号 | 检查是不是 for i in range(5): 少了冒号 |
IndentationError: expected an indented block | 循环体忘了缩进 | 循环体统一缩进 4 个空格 |
| 程序卡住不动(死循环) | while 的条件永远为真,没有让条件变假的代码 | 检查循环体里是否更新了条件变量;临时按 Ctrl+C 终止 |
IndexError 或 NameError | 循环变量名写错或越界访问 | 检查循环变量名、range 的范围 |
TypeError: 'int' object is not iterable | 把数字直接放进了 for(for i in 5:) | 数字不能遍历,要写成 for i in range(5): |