range(1, 6) 是 1 到 5,不含 6。
for i in range(100) 套 for j in range(i, 100) 实际只转 5050 次,
按 100×100 算会多算 4950 次。
上一节让程序选路,这一节让它重复。循环最容易错的两处:边界差一,和嵌套次数算错。
一、range 的三个参数
range 是最常用的循环来源,三个参数分别管起点、终点、步长:
- range(1, 6) 给 [1, 2, 3, 4, 5]——含头不含尾,没有 6。
- range(6) 给 0 到 5,起点省略就是 0。
- range(0, 10, 3) 给 [0, 3, 6, 9],步长 3。
- range(5, 0, -1) 给 [5, 4, 3, 2, 1],步长为负就倒着走。
「含头不含尾」是差一错误(off-by-one)的头号来源。要 1 到 100,就写 range(1, 101)。
二、for 和 while 各管一类事
for 管「已知要转多少次」;while 管「转到条件不成立为止」。
Demo 用两种写法各算一遍 1 加到 100,都给 5050。结果一样,适用场景不同。
for 天然不会死循环;while 忘了更新条件就死循环。
写 while 时先把「什么时候退出」写成注释,再动手。
while True 加 break 也是常见写法——把退出条件写在中间,比塞进 while 后面更清楚。
三、break 和 continue
两个都能改变流程,方向相反:
- break 直接跳出整个循环。
Demo 在 1 到 10 里找第一个能被 7 整除的数,看过的数是 [1, 2, 3, 4, 5, 6, 7]——到 7 就停了。
- continue 跳过本次剩下的语句,继续下一轮。Demo 留下奇数 [1, 3, 5, 7, 9]。
差一的是很容易搞混:break 之后循环结束,continue 之后循环继续。
写错一个,要么少处理一半数据,要么多算一轮。
四、嵌套循环的次数不能拍脑袋
这一条最有价值。Demo 写的是:for i in range(100) 里面套 for j in range(i, 100)。
实际转了多少次?5050 次。不是 10000 次。
因为内层的范围随外层缩小,第一次 100 次,第二次 99 次……最后 1 次。
按 100×100 算会多算 4950 次——差了将近一倍。
估算训练耗时、估算标注工时,用的都是这个数,差一倍就是差一倍的钱。
Demo 最后演示了 for-else:循环正常跑完才执行 else,被 break 打断就不执行。
37 被 37 整除,break 掉,else 没跑;97 在 2 到 49 里都不整除,走了 else。
这个语法不常用,但判断「找没找到」很干净:找到了就 break,没找到才走 else,
不用额外加一个标志变量。
五、动手 Demo:range 的边界、break 的时机、嵌套的次数
先打四种 range 的取值;再用 for 和 while 各算一遍 1 加到 100;
然后演示 break 与 continue 的差别;接着实算一个嵌套循环的真实次数并与 100×100 对比;
最后演示 for-else 的两种走向。
print(list(range(1, 6))) # [1, 2, 3, 4, 5]
print(list(range(0, 10, 3))) # [0, 3, 6, 9]
for i in range(1, 101):
s += i # 5050
cnt = 0
for i in range(100):
for j in range(i, 100):
cnt += 1 # 5050,不是 10000
for target in (37, 97):
for i in range(2, 50):
if target % i == 0:
break
else:
print(target, '走 else')
实跑输出:
--------------------------------------------------------------------
循环语句:range 的边界、break 的时机、嵌套的次数
--------------------------------------------------------------------
range(1, 6) [1, 2, 3, 4, 5]
range(6) [0, 1, 2, 3, 4, 5]
range(0, 10, 3) [0, 3, 6, 9]
range(5, 0, -1) [5, 4, 3, 2, 1]
range 含头不含尾——range(1, 6) 是 1 到 5,没有 6。
for 累加 1+...+100 5050
while 累加 1+...+100 5050
break 与 continue 的差别(在 1~10 里找第一个能被 7 整除的):
break:看过这些数 [1, 2, 3, 4, 5, 6, 7]
continue:留下的奇数 [1, 3, 5, 7, 9]
for i in 100:for j in range(i,100) 5050 次
直接写 100*100 会算成 10000 次(错了 4950 次)
嵌套循环的次数必须按内层的实际范围算,别拿外层乘外层。
for-else:循环正常跑完才执行 else,被 break 打断就不执行。
37:被 37 整除,break 掉
97:2~49 都不整除,走 else
四种 range 一眼看完,重点是第一行:range(1, 6) 没有 6。要 1 到 6 得写 range(1, 7)。
for 和 while 都给 5050。
同一个结果两种写法,while 那份多了一个「k 要加 1」的手工活,忘了就死循环。
break 那组看过的数是 [1, 2, 3, 4, 5, 6, 7],到 7 就停;
continue 那组留下 [1, 3, 5, 7, 9],偶数的被跳过。
嵌套那一组是本节重点:实算 5050 次,按 100×100 是 10000 次,差 4950 次。
约一半的工作量被错估。
for-else 两行:37 被 37 整除直接 break,else 不执行;
97 走完了 2 到 49 都不整除,else 执行。
30 秒实验
- 把
range(i, 100)改成range(100),重新数一遍次数,验证是 10000。 - 用
for-else写一个「在列表里找某元素」的函数,不用标志变量。 - 想一想:为什么估算训练时间时,嵌套循环的次数必须实算?
常见误区
- 「
range(1, 6)是 1 到 6」——含头不含尾,少了最后一个。 - 「两层 100 的循环就是一万次」——内层范围随外层变,可能只有一半。
- 「
break和continue都是跳出」——一个跳整轮,一个只跳本次。
自测三问(点开对答案)
1. `range(1, 6)` 给出哪些数? —— 1 到 5,含头不含尾,没有 6。 2. `break` 和 `continue` 的区别是什么? —— `break` 结束整个循环,`continue` 只跳过本次剩余语句。 3. `for i in range(100)` 套 `range(i, 100)` 一共转多少次? —— 5050 次,等于 100+99+…+1。语法六件套讲完,下面进实战:五个小实例,每个都带真实运行结果。
- ☐ (本节完,下一节 3.3.1 实例1:使用Python计算业绩提成奖金)