上一篇结尾你写好了一个把关脚本:数据是空的、太少、正常,各说各的话。可它一次只能判断一份数据。真实的报表有几百行,每一行都要做类似的检查或处理——你不可能把那段代码复制八百遍,复制出来的东西只要改一次规则,就得回头改八百处。
这一篇给程序装上第一台“自动重复机”:for 循环。今天只把一件事讲透——怎么让一段代码按你指定的次数一遍一遍地跑,以及每一遍到底发生了什么。
先把结构写出来
最短的一个循环长这样:
1for 次数 in range(5):
2 print("滴——正在读取数据……")运行它,你会发现这句话被打印了 5 遍,而不是一遍。
先看结构。for 这一行以英文冒号结尾,中间分成三段:for 关键字、一个自己起的名字(叫它 循环变量)、以及 in range(5)。下一行缩进 4 个空格,是 循环体——就是那部分要被反复执行的代码。
这个结构和上一篇的 if 是同一个套路:冒号开门,缩进圈地。区别只在含义——if 后面缩进的东西“条件成立时执行一次”,for 后面缩进的东西“一遍又一遍地执行”。
range() 交出来的到底是什么
range(5) 不是让程序“循环 5 次”的开关,它在做一件更具体的事:生成一串数字交出去。range(5) 给出的五个数字是
0、1、2、3、4
五个数字,所以循环体跑五遍。注意它从 0 开始,而且拿不到 5。1
要让数字从 1 开始、数到 5 为止,写成 range(1, 6)——它给出 1、2、3、4、5。第二个参数是 终点,但终点不算在内,所以想数到 5 就必须写 6。这个“差一”是初学最常见的错误来源,记住一句话就够了:range(a, b) 给出的是从 开始、不到 的整数。
一遍一遍,到底发生了什么
看这个会真正用上数字的例子:
1for 序号 in range(1, 4):
2 print(f"第 {序号} 次巡检,设备状态正常。")
3print("巡检结束。")输出四行:三次“第 N 次巡检”,最后一行“巡检结束。”。
range(1, 4) 交出的数字是 1、2、3。for 拿到这串数字后,每一轮固定做三件事:
- 取出下一个数字,装进循环变量
序号; - 把缩进块里的代码完整执行一遍;
- 回头取下一个数字,直到数字取完——循环结束,程序接着执行循环后面那行。
| 轮次 | 循环变量 序号 | 这一轮打印的内容 |
|---|---|---|
| 第 1 轮 | 1 | 第 1 次巡检,设备状态正常。 |
| 第 2 轮 | 2 | 第 2 次巡检,设备状态正常。 |
| 第 3 轮 | 3 | 第 3 次巡检,设备状态正常。 |
| 数字取完 | —— | 巡检结束。 |
画成流程图是这样:
这张图里有两个关键点。第一,循环体的入口在每一轮都相同:第 2 轮不是接着第 1 轮往下走,而是回到循环体开头重新走一遍,唯一变的是循环变量里的值。第二,循环变量是普通变量,只不过每轮开头会被重新赋值一次 2。所以循环结束后,序号 并不会消失,它保留着最后那个数字 3;反过来,如果 range() 一个数字都给不出来(比如 range(0)),循环体一次都不执行,循环变量也就根本没被赋过值。
循环体里可以放什么
循环体里能放多少行都没关系,只要是同样的缩进,它们就一起被重复。而且循环体里可以放上一篇学的整套 if 判断——这正是“对一批数据逐条把关”需要的组合。
1for 件数 in range(1, 6):
2 if 件数 < 3:
3 print(f"{件数} 件:数量太少,需要核对。")
4 else:
5 print(f"{件数} 件:正常。")这里出现了两层缩进,要看清谁管谁:if 和它的 else 缩进 4 个空格,属于循环体,每一轮都要走一遍;两个 print 缩进 8 个空格,分别属于 if 和 else,每轮里只会执行其中之一。运行结果是:1 件、2 件说“需要核对”,3 件、4 件、5 件说“正常”——五轮,五句输出。
说白了,循环负责“重复几遍”,if 负责“这一遍说什么”,两者各管一段,靠缩进分层。
这里得老实交代一点:上面的“件数”是从 range() 里临时造出来的数字,只为演示机制。真实工作里这些数字来自表格的一列,等学了能装一串数据的容器,把 range(1, 6) 换成那份数据就能直接用。这是下一篇的事。
常备一个“账本”:循环里做累加
再学一个几乎处处要用的招式。假如要算 :
1合计 = 0
2for 份数 in range(1, 5):
3 合计 = 合计 + 份数
4print(f"1 到 4 的和是 {合计}")输出“1 到 4 的和是 10”。关键在于 合计 = 0 这一行:它在 循环之前、且 没有缩进,所以只执行一次,相当于先准备好一个空账本。之后每一轮,循环体里那行 合计 = 合计 + 份数 都在做同一件事:把这一轮的数字加到账本上。
| 轮次 | 份数 | 执行后 合计 的值 |
|---|---|---|
| 开始前 | —— | 0 |
| 第 1 轮 | 1 | 1 |
| 第 2 轮 | 2 | 3 |
| 第 3 轮 | 3 | 6 |
| 第 4 轮 | 4 | 10 |
对照这张表能看清一件事:合计 从头到尾只有一个,每一轮都在改它,所以值会累积下来。如果把 合计 = 0 挪进循环体(多缩进 4 个空格),它每轮开头都被清零,前面的累加全部作废,最后只剩最后一轮的结果 4,而不是 10。准备变量的那行在循环外、干活的那行在循环内,这是两种缩进带来两种结果的最典型一处。
三个最容易踩的坑
一、缩进决定了哪几行被重复。 这两段代码输出的行数完全不同:
1for 序号 in range(3):
2 print(f"处理第 {序号} 份")
3print("全部处理完毕")第一段打印“处理第 1/2/3 份”,然后打印一次“全部处理完毕”。如果把最后那行也缩进 4 格,它就成了循环体的一部分,会被打印三次——一句话被说三遍,程序不报错,但你想要的“收尾提示”变成了“重复播报”。
二、重复次数不等于终点那个数字。 range(1, 5) 跑 4 遍(1、2、3、4),不是 5 遍。写成 range(1, 6) 才是 5 遍。写完数一下括号里到底给出几个数,比背口诀可靠。
三、在循环体里给循环变量重新赋值没有用。 比如在循环里写一行 序号 = 100,下一轮开头 序号 还是会被下一个数字覆盖掉,循环该跑几遍还是几遍 2。原因是每一轮的循环变量都由 for 那一行重新指定,你在循环体里改的是它“这一轮的临时值”,改不了循环的节奏。
今天就到这里
现在你手里有三个能力:变量记住数据、if 看情况走不同的路、for 把同一段代码重复指定的次数。把把关脚本套进循环,已经能按次数逐条检查并累计结果了——只是这些数据目前还得靠 range() 造出来。
但这台重复机还带着一个明显的限制:重复的次数要么是你写死的(range(5)),要么是你数好写进去的(range(1, 6))。 现实里的重复通常不这样——表格有多少行就该跑多少遍,今天是 200 行,明天是 1500 行,你不会想每天先数一遍再改代码。
要突破这一步,得让 for 直接跟一份数据打交道,而不是先跟一串数字打交道。那需要的是一种能装下一整列数据的容器,也是下一篇的主题。