Skip to content

Python for 循环 ​

上一节使用 while 控制重复过程,但需要我们自己准备循环变量、判断条件和更新操作。

现在遇到两个常见任务:

  • 已知要重复多少次,例如连续输出 5 次练习记录;
  • 已经有一组内容,例如字符串,需要逐个取出并处理。

如果每轮都手动取值或更新,代码很快会变得重复。for 可以自动取出下一项,range() 可以生成需要的重复次数。本章再继续解决筛选内容、选择循环类型和处理多层重复的问题。

遍历一组内容:for ​

先解决第一个任务:依次打印字符串 Python 中的每个字符。

for 循环可以先理解为:从一组内容中按顺序取值,每取出一个值,就执行一次循环体。

text
for 变量 in 一组内容:
    每次取值后执行的代码

for 循环语法结构剖析图

python
for char in "Python":
    print(char)

运行结果:

text
P
y
t
h
o
n

循环开始后,char 会依次得到 "P"、"y"、"t"、"h"、"o" 和 "n"。字符串中的字符全部取完后,循环自动结束。

这里不需要提前定义 char,也不需要手动修改它。for 会在每轮循环开始时自动取出下一个值。

控制重复次数:range() ​

如果手里没有现成的一组内容,只知道“要执行几次”,应该怎样让 for 按次数运行?

需求:让代码固定执行 5 次,并输出每轮拿到的编号。通常会让 for 配合 range() 使用。

python
for number in range(5):
    print(number)

运行结果:

text
0
1
2
3
4

range(5) 依次产生 0、1、2、3、4,所以循环执行 5 次。最容易记错的是:

range() 包含起始值,不包含结束值。

range() 的三种写法 ​

range() 有三种常用写法:

python
range(stop)
range(start, stop)
range(start, stop, step)
参数作用默认值
start起始值,会被包含0
stop结束值,不会被包含必须提供
step每次变化的步长1

for 可以直接遍历 range() 产生的整数范围,不需要先使用 list() 转换。

只提供一个参数时,这个参数表示结束值:

python
for number in range(5):
    print(number, end=" ")

运行结果:

text
0 1 2 3 4

同时提供起始值和结束值,可以生成 1 到 5:

python
for number in range(1, 6):
    print(number, end=" ")

运行结果:

text
1 2 3 4 5

第三个参数用于控制步长。例如,从 0 开始,每次增加 2:

python
for number in range(0, 10, 2):
    print(number, end=" ")

运行结果:

text
0 2 4 6 8

步长也可以是负数。此时起始值要大于结束值:

python
for number in range(5, 0, -1):
    print(number, end=" ")

运行结果:

text
5 4 3 2 1

range() 整数序列生成机制与对比图

如果只关心重复次数,不需要使用每轮产生的数字,可以把循环变量写成 _:

python
for _ in range(3):
    print("继续练习")

_ 仍然是变量,只是按照常见约定表示“这个值不会在后面使用”。

遍历与筛选 ​

逐个取出值之后,如果还要挑出满足条件的内容,就把 for 和 if 组合起来。

有时我们不只是要取出每个值,还要检查当前值是否符合条件。“遍历”就是按照某种顺序,把一组内容逐个取出。除了 range(),for 还可以遍历字符串,以及后续会学习的列表、元组、集合和字典。

下面统计字符串中包含多少个字母 o:

python
text = "hello world"
count = 0

for char in text:
    if char == "o":
        count += 1

print(f"字母 o 出现了 {count} 次")

运行结果:

text
字母 o 出现了 2 次

for 遍历字符串并使用 if 筛选字符的流程图

这段代码把循环和判断组合在一起:for 负责逐个取出字符,if 负责判断当前字符是不是 "o"。

for 与 while 的选择 ​

同一个重复任务有时两种循环都能完成,应该根据什么来选择?

for 和 while 都能实现循环,但它们适合处理的问题不同:

场景更适合的循环
按顺序取出一组内容for
已经明确重复次数for
条件成立时持续执行while
无法提前确定循环次数while

例如:

  • 连续完成 5 次练习,可以使用 for
  • 逐个检查字符串中的字符,可以使用 for
  • 持续接收输入,直到用户输入 q,更适合使用 while

这不是强制规则,但能帮助我们快速选择结构。只要循环过程依赖的是“一组待处理的内容”,通常优先考虑 for。

嵌套 for:分层处理 ​

如果任务同时包含“多行”和“每行多个内容”两层重复,怎样避免把每一行都手写?

如果一个任务同时有“多行”和“每行多个内容”两层重复,就需要在 for 内再写一个 for。和嵌套 while 一样,外层循环通常控制行,内层循环负责每一行中的重复内容。

案例:星号三角形 ​

需求:输出一个正左角形。

text
*
**
***
****
*****
python
for row in range(1, 6):
    # 当前是第几行,就打印几颗星
    for col in range(1, row + 1):
        print("*", end="")

    # 当前行打印完成后换行
    print()

外层的 row 依次得到 1 到 5,负责决定当前是第几行。内层循环负责打印当前行的星号。

当 row 等于 3 时:

  1. range(1, row + 1) 相当于 range(1, 4)
  2. col 依次得到 1、2、3
  3. 内层循环执行 3 次,打印 3 颗星
  4. 内层循环结束后,最后一个 print() 负责换行

这里写成 row + 1,是因为 range() 不包含结束值。

嵌套 for 循环使用 row 和 col 输出星号三角形的关系图

练习:用空格调整图形对齐

在星号左侧补充空格,把图形调整为正右角形:

text
    *
   **
  ***
 ****
*****

可以先分析每一行的组成:

  • 第 1 行:4 个空格,1 颗星
  • 第 2 行:3 个空格,2 颗星
  • 第 5 行:0 个空格,5 颗星

先根据这个规律自己完成代码,再展开参考答案。

参考答案
python
for row in range(1, 6):
    # 行号越大,左侧空格越少
    for _ in range(5 - row):
        print(" ", end="")

    # 当前是第几行,就打印几颗星
    for _ in range(row):
        print("*", end="")

    print()

前面已经分别解决了遍历、筛选和嵌套循环。接下来用两个完整任务把这些方法串起来。

案例:九九乘法表 ​

需求:输出九九乘法表,并让第 n 行只显示前 n 个乘法表达式。

上一节使用嵌套 while 输出了九九乘法表。换成 for 后,不再需要手动初始化和更新 row、col。

python
for row in range(1, 10):
    # 当前是第几行,就输出几个乘法表达式
    for col in range(1, row + 1):
        print(f"{col} × {row} = {col * row}", end="\t")

    print()

运行逻辑与上一节相同:

  1. 外层循环控制 9 行
  2. 内层循环从 1 遍历到当前行号
  3. 每轮内层循环输出一个乘法表达式
  4. 当前行结束后,使用 print() 换行

当 row 等于 9 时,range(1, row + 1) 就是 range(1, 10),内层循环会输出 9 个乘法表达式。

案例:寻找水仙花数 ​

需求:找出所有三位水仙花数。水仙花数是一个三位数,它每一位数字的三次方之和等于它本身。例如:

text
153 = 1³ + 5³ + 3³

要找出所有三位水仙花数,可以把任务拆成三步:

  1. 使用 for 依次取出 100 到 999
  2. 分别计算当前数字的百位、十位和个位
  3. 使用 if 判断三位数字的三次方之和是否等于原数字

先练习遍历所有三位数:

python
for number in range(100, 1000):
    print(number)

接着加入数位拆分和判断:

python
for number in range(100, 1000):
    hundreds = number // 100
    tens = number // 10 % 10
    ones = number % 10

    if hundreds ** 3 + tens ** 3 + ones ** 3 == number:
        print(number)

运行结果:

text
153
370
371
407

以 153 为例:

  • 153 // 100 得到百位数字 1
  • 153 // 10 % 10 得到十位数字 5
  • 153 % 10 得到个位数字 3

for 负责检查每一个三位数,if 只保留满足条件的数字。这样就把“遍历”和“判断”各自的职责分开了。

常见问题 ​

range() 不包含结束值 ​

range(1, 5) 产生的是 1、2、3、4,不包含 5。如果需要得到 1 到 5,结束值要写成 6。

循环变量的自动更新 ​

for 会在每轮开始时自动为循环变量取下一个值。通常不需要再写 number += 1,否则代码容易让人误以为它能控制下一轮取值。

python
for number in range(3):
    print(number)

小结 ​

本章沿着五个问题推进:

  1. 一组内容如何逐个处理?使用 for
  2. 重复次数如何控制?使用 range(),并牢记结束值不包含在内
  3. 如何只保留满足条件的内容?用 for 配合 if
  4. for 和 while 如何选择?看任务依赖内容还是条件
  5. 多行多列的任务如何拆分?用嵌套循环让外层控制行、内层处理每行内容