跳到主要内容

2.3 周而复始的循环

知识点​

1.为什么需要循环​

重复性的工作:求 1 到 100 的和、打印 50 名学生的成绩、判断 1 到 1000 中的素数……如果一条一条写语句,代码量不可接受。

循环结构:在满足条件的情况下,反复执行同一段语句。

流程图特征:流程线从后往前回到某一步,形成回路,且必须有出口(否则违反算法的有穷性)。

循环三要素(写循环前必须先想清楚):

  1. 循环变量的初值;
  2. 循环条件(什么时候继续);
  3. 循环变量如何更新(怎么变、变多少)。

三要素缺一个,循环就转不起来或停不下来。

2.for 循环与 range 函数​

(1)基本格式​

for 循环变量 in 序列:
循环体

执行流程:从序列中依次取出每个元素赋给循环变量,每取一个就执行一次循环体,取完为止。

(2)range 函数(重点,必考)​

格式:range(起始值, 终止值, 步长)

写法产生的序列循环次数
range(5)0, 1, 2, 3, 45 次(默认从 0 开始)
range(1, 6)1, 2, 3, 4, 55 次(含 1,不含 6)
range(1, 10, 2)1, 3, 5, 7, 95 次
range(10, 0, -2)10, 8, 6, 4, 25 次(步长为负,倒着走)
range(0)空0 次(循环体不执行)

三条核心规则:

  1. 左闭右开:包含起始值,不包含终止值——range(1, 6) 是 15,不是 16;
  2. 步长默认 1,可正可负,不能为 0;
  3. 循环次数 = (终止值 - 起始值) / 步长 的向上取整(正步长时)。

记忆口诀:"含头不含尾"——这是 Python 循环最容易被扣分的地方。

常用对照:

需求写法
1 到 100(含 100)range(1, 101)
1 到 n(含 n)range(1, n + 1)
0 到 n-1range(n)
偶数 2~100range(2, 101, 2)
倒序 100~1range(100, 0, -1)

(3)遍历字符串与列表​

for ch in "Python":
print(ch) # P y t h o n 各占一行

for name in ["张三", "李四", "王五"]:
print(name)

for … in 的本质:遍历(逐个访问)序列中的元素,不需要关心下标。

需要下标时用 range(len(...)):

s = "hello"
for i in range(len(s)):
print(i, s[i])

3.while 循环​

(1)基本格式​

while 条件:
循环体 # 循环体中必须有让条件趋于假的操作

执行流程:先判断条件→ 成立则执行循环体 → 再回到条件判断 → ……直到条件不成立。

特点:先判断,后执行;条件一开始就不成立时,循环体一次也不执行。

(2)与 for 的选择​

场景推荐原因
已知循环次数(1~100、数组遍历)for次数明确,代码简洁,不会死循环
次数未知,靠条件结束(直到猜对、直到精度满足)while无法预先知道要转几次
必须至少执行一次while(或 do-while 思想)先做再判断

记忆:"次数确定用 for,条件控制用 while"。

(3)while 的三个必备动作​

i = 1 # ① 循环变量赋初值
while i <= 100: # ② 循环条件
total = total + i
i = i + 1 # ③ 循环变量更新(漏了就死循环)

死循环:条件永远为真,程序卡住不结束。

i = 1
while i <= 100:
print(i) # 忘了 i = i + 1,永远打印 1

排查死循环:检查循环变量有没有更新、更新方向对不对(条件写 i <= 100 却写 i = i - 1 也是死循环)、条件里有没有用到不会变的量。

强制结束:在交互式环境或终端按 Ctrl + C。

4.两种基本模式:累加与计数​

(1)累加(求和、求积)​

模板:

total = 0 # 累加器初值必须是 0(求积则为 1)
for i in range(1, 101):
total = total + i # 等价于 total += i
print(total) # 5050

为什么初值必须是 0:0 + 任何数 不改变结果;若初值写成 1,结果会多 1。

求积的初值必须是 1(1 * 任何数 不变),这是阶乘的写法:

n = int(input("n = "))
f = 1
for i in range(1, n + 1):
f = f * i
print(f"{n}! = {f}")

(2)计数(统计个数)​

模板:

count = 0
for i in range(1, 101):
if i % 3 == 0:
count += 1 # 满足条件才加 1
print("1~100 中 3 的倍数有", count, "个")

要点:计数器初值 0,在 if 内部才加 1(写在 if 外面就变成统计总次数)。

(3)求最值​

模板:先把第一个数当作"当前最大",再逐个比较更新。

nums = [78, 92, 65, 88, 95]
big = nums[0]
for x in nums:
if x > big:
big = x
print("最大值:", big)

易错:初值不能设成 0(若全是负数,结果会错),应取序列的第一个元素。

5.break 与 continue​

语句作用类比
break立即结束整个循环,跳到循环之后的语句"不干了,走人"
continue结束本次循环,跳过剩余语句,直接进入下一次"这次先跳过,继续下一个"
# break:找到第一个能被 7 整除的数就停
for i in range(1, 100):
if i % 7 == 0:
print("找到了:", i)
break # 输出 7,然后整个循环结束

# continue:跳过 3 的倍数
for i in range(1, 11):
if i % 3 == 0:
continue # 跳过 3、6、9
print(i, end=" ") # 输出 1 2 4 5 7 8 10

break 与 return 的差别:break 只跳出当前这一层循环;函数里的 return 会直接结束整个函数(见 2.4)。

循环的 else 子句(可了解):for … else 或 while … else 中的 else 部分,在循环正常结束(不是被 break 中断)时执行。常用于"找素数、找因子"的判定,考试中较少出现。

6.循环嵌套​

定义:循环体中再写一个循环。

执行规律:外层走一步,内层走完一整圈。总执行次数 = 外层次数 × 内层次数。

# 2-7 九九乘法表
for i in range(1, 10): # 外层:行
for j in range(1, i + 1): # 内层:列,每行到 i 为止
print(f"{j}×{i}={i*j}", end="\t")
print() # 一行结束换行

要点:

  1. 内层循环的 range 可以用外层变量(如 range(1, i + 1)),这是打印三角形、乘法表的关键;
  2. 每层缩进各不相同(外层 4 空格,内层 8 空格);
  3. print() 空打印用于换行。

常见图形题:

# 打印 5 行金字塔星号
for i in range(1, 6):
print(" " * (5 - i) + "*" * (2 * i - 1))

嵌套的效率:两层嵌套的时间是平方级增长(n × n),三层就是立方级——这是 4.1 讲时间复杂度的直观例子。

7.典型算法(本小节能力落点)​

(1)穷举(枚举)​

思路:把所有可能的情况一一列举,逐个检验,符合条件的就输出。

# 2-8 百钱百鸡(简化版):公鸡 5 元、母鸡 3 元、小鸡 1 元 3 只,100 元买 100 只
for x in range(0, 21): # 公鸡最多 20 只
for y in range(0, 34): # 母鸡最多 33 只
z = 100 - x - y
if z % 3 == 0 and 5 * x + 3 * y + z // 3 == 100:
print(x, y, z)

要点:穷举的关键是"缩小枚举范围"(用总数量约束减少一层循环),否则效率极低。

(2)辗转相除法(求最大公约数)​

# 2-9 求 m、n 的最大公约数
m, n = 48, 18
while n != 0:
m, n = n, m % n
print("最大公约数:", m) # 6

原理:gcd(m, n) = gcd(n, m % n),直到余数为 0,此时的除数就是最大公约数。

(3)判断素数​

n = int(input("请输入一个大于 1 的整数:"))
is_prime = True
for i in range(2, int(n ** 0.5) + 1): # 只需试到根号 n
if n % i == 0:
is_prime = False
break
print("是素数" if is_prime else "不是素数")

两个优化点:只需试到 n 的平方根(因数成对出现);找到因数就 break。

(4)斐波那契数列(递推)​

a, b = 1, 1
for i in range(10):
print(a, end=" ")
a, b = b, a + b

要点:用两个变量滚动往前推,是"迭代"思想的雏形(第 4 单元展开)。

(5)水仙花数(穷举 + 数位拆分)​

for n in range(100, 1000):
a = n // 100 # 百位
b = n // 10 % 10 # 十位
c = n % 10 # 个位
if a**3 + b**3 + c**3 == n:
print(n, end=" ")

8.易错点清单​

序号错误说明正确
1for i in range(1, 100) 想求 1~100 的和少了 100(左闭右开)range(1, 101)
2while 缺循环变量更新死循环循环体内加 i = i + 1
3累加器初值写 1结果多 1初值 0
4求积初值写 0结果永远是 0初值 1
5计数器 count += 1 写在 if 外统计的是总次数放进 if 内
6求最大值初值设 0全负数时出错取第一个元素
7break 与 continue 混用一个"整个退出"、一个"跳过本次"按语义选
8循环体缩进不一致IndentationError 或逻辑错统一 4 空格,逐层递增
9range(1, 10, -1)步长为负但起始小于终止 → 空循环用 range(10, 0, -1)
10range(0)一次也不执行确认边界是否写错
11循环嵌套中内外层缩进相同内层不在外层里内层多缩进 4 空格
12在循环里反复 input() 却没提示用户不知道要输几次加提示或用固定次数

9.速查表​

序号考点结论
1循环三要素初值、条件、更新
2for 语法for 变量 in 序列:
3range(5)0~4,共 5 次
4range(1, 6)1~5,共 5 次
5range 规则左闭右开(含头不含尾)
6range(1, 101)1 到 100
7range(10, 0, -2)10 8 6 4 2
8while 特点先判断后执行,可能一次都不执行
9次数确定用for
10条件控制用while
11死循环原因循环变量未更新或方向错
12累加器初值0
13累乘(阶乘)初值1
14求最值初值第一个元素
15break结束整个循环
16continue跳过本次,继续下一次
17嵌套执行次数外层次数 × 内层次数
18九九乘法表内层range(1, i + 1)
19素数判断优化试到 根号 n,找到因数 break
20最大公约数辗转相除(m, n = n, m % n)
21穷举优化关键缩小枚举范围
22强制终止运行Ctrl + C

10.课堂提示(讲课参考)​

  • 第一节课只讲 for 求 1~100 的和,让学生手算 5050 的高斯法,再用循环实现——"机器替人重复"的感受最直接。
  • range 边界用"数台阶"比喻:从第 1 级走到第 6 级,实际只走 5 步(1、2、3、4、5),第 6 级是"终点不算"。
  • 死循环现场演示:漏写 i = i + 1,屏幕疯狂滚动,再教 Ctrl+C 终止,学生一辈子忘不了。
  • 九九乘法表是嵌套的最佳载体:先打印 5 行 5 列方阵,再改成三角形(内层 range(1, i+1)),改一个参数就懂"内外层联动"。
  • 把"累加/计数/求最值"三个模板做成卡片让学生背,后面第 4 单元的所有算法题都靠这三个模板打底。