循环语句:for循环、while循环

一句话概述

循环语句让计算机自动重复执行代码,处理批量数据、遍历集合、累积计算等重复性任务。Python 提供两种主要循环结构:for 循环擅长遍历序列(列表、元组、字符串等)中的每一个元素,while 循环则根据条件是否成立来决定是否继续循环。在 AI 开发中,循环用于遍历训练数据、迭代优化模型参数、批量处理数据集等核心场景。

💡 核心要点:① for 循环逐个取出可迭代对象中的元素,处理完自动结束 ② range() 是 for 循环的最佳搭档,快速生成整数序列 ③ while 循环在条件为 True 时持续执行,适合不知道循环次数的场景 ④ 循环是 AI 训练中遍历数据集(epoch/batch)的核心机制

教学与演示

一、for 循环:遍历序列的利器

是什么for 循环按顺序从可迭代对象(列表、元组、字符串、range 等)中逐个取出元素,赋值给循环变量,然后执行循环体内的代码。当所有元素被遍历完时,循环自动结束。

大白话 就像点名——老师拿着花名册,从第一个同学开始依次点名,点到谁谁站起来回答。for 循环就是程序的花名册,逐个处理列表中的每一项。

为什么:程序经常需要批量处理数据——给全班同学算平均分、给所有图片打水印、给每行文本做分词。如果手动对每个元素写重复代码,既低效又容易出错。for 循环让你写一次逻辑,自动应用到所有元素上。

怎么做

import numpy as np

# 模拟 AI 训练中的批处理:遍历一个小型数据集
# 生成 5 个模拟数据样本的特征向量(每个样本 3 个特征)
np.random.seed(42)  # 固定随机种子,让结果可复现(AI实验的常见做法)
samples = np.random.randint(0, 100, size=(5, 3))  # 生成 5x3 的矩阵
print("📊 数据集(5个样本,每个3个特征):")
print(samples)
print()

# for 循环遍历每一行(每个样本)
print("--- 逐个处理每个样本 ---")
for i, sample in enumerate(samples):  # enumerate 同时给出索引和值
    # sample 是当前样本的特征向量,是一个包含3个元素的 numpy 数组
    total = np.sum(sample)  # 计算该样本所有特征值之和(模拟特征聚合)
    mean_val = np.mean(sample)  # 计算该样本的均值
    print(f"样本 {i+1}:{sample} → 总和={total}, 均值={mean_val:.1f}")

什么用:在 AI 模型训练中,每个 epoch 都要遍历整个训练集的所有样本——for batch in dataloader: 是 PyTorch 中最常见的循环模式。在图像处理中,for 循环遍历文件夹中的所有图片进行批量预处理(如调整大小、归一化)。在 NLP 中,for 循环遍历文档中的每个句子进行分词处理。

二、range():for 循环的最佳搭档

是什么range(start, stop, step) 返回一个不可变的整数序列对象,通常与 for 循环配合使用来控制循环次数。它按需生成数字,不占用大量内存——即使 range(1000000) 也不会创建 100 万个整数的列表。

大白话 range 就像体育课上的报数——「从 1 开始,报到 10 结束」。你不需要提前写好 1 到 10 的数字卡片,range 在需要的时候才告诉你下一个数字是什么。

为什么:很多循环不需要遍历已有数据,只需要「重复 N 次」。比如训练 100 个 epoch、生成 50 个随机验证样本、模拟 1000 次蒙特卡洛实验。range() 提供了最简洁的方式来控制固定次数的循环。

怎么做

import numpy as np

# range(stop):从 0 开始到 stop-1,步长为 1
print("range(5):从0到4")
for i in range(5):  # 等价于 [0, 1, 2, 3, 4]
    print(f"  第 {i+1} 次迭代", end="")
print("\n")

# range(start, stop):从 start 开始到 stop-1
print("range(2, 7):从2到6")
for i in range(2, 7):
    print(f"  值 = {i}", end="")
print("\n")

# range(start, stop, step):指定步长
print("range(0, 10, 2):0到9,每隔2个(偶数)")
for i in range(0, 10, 2):
    print(f"  值 = {i}", end="")
print("\n")

# 在实际AI场景中:模拟训练过程的 epoch 迭代
print("--- 模拟AI训练过程 ---")
epochs = 5  # 训练总轮数
for epoch in range(1, epochs + 1):  # 从第1轮开始
    # 模拟每轮训练的损失值(Loss)逐渐下降
    loss = np.exp(-epoch * 0.5) + np.random.uniform(0, 0.1)  # 指数衰减 + 随机噪声
    print(f"Epoch {epoch}/{epochs} → Loss: {loss:.4f}")
print("训练完成!")

什么用:在 AI 中,for epoch in range(num_epochs) 控制模型训练的轮数。在模型评估中,使用 for seed in range(10) 进行多次随机种子实验取平均结果。在超参数搜索(Grid Search)中,range() 遍历学习率、batch size 等超参数的所有候选值。在数据增强中,range(augment_times) 控制每张图片生成多少个增强版本。

三、while 循环:条件驱动的循环

是什么while 循环在每次迭代前检查条件表达式——如果为 True 则执行循环体,然后再次检查条件;如果为 False 则退出循环。循环次数不确定,完全取决于条件何时变为 False。

大白话 while 就像「吃到饱为止」——你不知道自己会吃几碗,但只要还没饱(条件为 True)就继续吃。for 是「把这盘吃完」,while 是「吃到饱为止」。

为什么:很多场景下,循环次数无法提前确定——游戏要持续运行直到玩家退出、AI 模型要训练到损失不再下降为止、网络请求要重试直到成功。while 循环就是为这种「循环到条件满足」的场景而生。

怎么做

import numpy as np

# 模拟 AI 模型训练中的 Early Stopping(早停法)机制
# 模型持续训练,直到连续 3 次验证损失不再下降就停止
print("--- 模拟 Early Stopping 训练 ---")
patience = 3  # 容忍次数:连续3次不改善就停止
no_improve_count = 0  # 计数器:记录连续不改善的次数
best_loss = float('inf')  # 最佳损失值,初始化为无穷大
epoch = 0  # 当前轮次

while no_improve_count < patience:  # 只要连续不改善次数 < 容忍次数,就继续训练
    epoch += 1
    # 模拟验证损失:整体趋势下降,但有随机波动
    current_loss = 0.5 * np.exp(-epoch * 0.3) + np.random.uniform(0, 0.15)
    current_loss = round(current_loss, 4)
    
    if current_loss < best_loss:  # 损失改善了!
        best_loss = current_loss  # 更新最佳损失
        no_improve_count = 0  # 重置不改善计数器
        status = "✅ 改善"
    else:  # 损失没有改善
        no_improve_count += 1  # 不改善计数 +1
        status = f"❌ 未改善 ({no_improve_count}/{patience})"
    
    print(f"Epoch {epoch} | Loss: {current_loss:.4f} | Best: {best_loss:.4f} | {status}")

print(f"\n🛑 训练停止!共训练 {epoch} 轮,最佳 Loss: {best_loss:.4f}")

什么用:Early Stopping(早停法)是 AI 训练中最经典的 while 循环应用——「当验证损失不再下降时停止训练」,防止过拟合。在强化学习中,while 循环驱动智能体与环境持续交互直到 episode 结束。在数据爬取中,while 循环实现分页抓取直到没有更多数据。在超参数优化(如贝叶斯优化)中,while 循环持续搜索直到达到指定的试验次数或效果不再提升。

四、循环中的 else 子句

是什么:Python 的 for 和 while 循环都支持一个独特的 else 子句——当循环正常结束(没有被 break 打断)时,执行 else 块中的代码。如果循环被 break 提前终止,else 块不会执行。

大白话 就像快递员送包裹——如果所有包裹都成功送达(正常结束),就发「今日配送完毕」通知(else);如果中途遇到问题提前收工(break),就不发这个通知。

为什么else 子句常用于「搜索未找到」的场景——遍历列表找某个元素,如果找遍了都没找到(正常结束),就在 else 中给出「未找到」的处理。这比设置一个 found 标志变量更加优雅。

怎么做

import numpy as np

# 模拟在 AI 模型评估指标中查找是否存在过拟合风险
# 生成一组验证损失值
np.random.seed(123)
val_losses = np.random.uniform(0.2, 0.8, size=8)  # 8个epoch的验证损失
val_losses = np.round(val_losses, 4)
print("📈 验证损失序列:", val_losses)

# for-else:查找连续上升的迹象(过拟合信号)
# 过拟合的典型信号:验证损失连续上升
print("\n--- 检测过拟合风险 ---")
rise_count = 0
for i in range(1, len(val_losses)):  # 从第2个元素开始比较
    if val_losses[i] > val_losses[i-1]:  # 当前损失 > 上一个,说明在上升
        rise_count += 1
        print(f"  Epoch {i+1}: {val_losses[i]:.4f} > {val_losses[i-1]:.4f} ↑上升 ({rise_count}次)")
        if rise_count >= 3:  # 连续上升3次,认为过拟合风险较高
            print(f"\n⚠️ 连续 {rise_count} 次上升,存在过拟合风险!")
            break  # 提前终止检查,else 块不会执行
else:  # for 正常结束(没有 break)时执行
    print(f"\n✅ 未检测到连续3次上升,过拟合风险较低")

# while-else:查找质数(另一种经典用法)
print("\n--- while-else 示例:查找质数 ---")
n = 29  # 要检查的数字
divisor = 2  # 从2开始除
while divisor * divisor <= n:  # 只需检查到 sqrt(n)
    if n % divisor == 0:  # 找到了因数,说明不是质数
        print(f"{n} 能被 {divisor} 整除,不是质数")
        break  # 提前退出
    divisor += 1  # 尝试下一个除数
else:  # while 正常结束,说明没找到任何因数
    print(f"{n} 是质数 ✅")

什么用:在 AI 异常检测中,遍历传感器数据序列查找异常点——如果正常遍历完未发现异常(else),则标记数据为正常批次。在模型搜索中,遍历候选模型架构列表寻找满足性能要求的模型——如果全部检查完仍未找到(else),则扩大搜索范围。在数据验证中,检查数据集所有样本是否通过质量检查——全部通过才执行后续训练流程。

概念关系图谱

概念核心含义与AI的关系关联概念
for 循环遍历可迭代对象中的每个元素遍历 DataLoader 中的 batch 数据可迭代对象、in
while 循环条件为 True 时持续执行Early Stopping、强化学习环境交互条件表达式、break
range()惰性生成整数序列控制 epoch 轮数、超参数遍历for 循环
enumerate()同时获取索引和值记录训练步数、batch 编号for 循环
可迭代对象能被 for 遍历的对象Dataset、DataLoader 的设计基础list、tuple、str
循环 else循环正常结束(非break)时执行搜索未找到时的兜底处理for、while、break
epoch训练中完整遍历一次数据集深度学习训练的核心概念for、range
迭代重复执行代码块的过程梯度下降的多次参数更新循环

重点答疑

Q1: for 循环和 while 循环什么时候用哪个?

简单原则:知道循环次数用 for,不知道用 while。具体来说:遍历列表、字典、文件行等已知集合时用 for;等待某个条件成立(如用户输入正确密码、模型损失降到阈值以下)时用 while。如果硬要用 for 写 while 的场景,就得写 while True: if 条件: break——这其实等于把 while 又请回来了。

Q2: 循环中的 break、continue 和 else 会互相影响吗?

是的。break 会跳出循环,导致 else 块不执行。continue 只是跳过本轮剩余代码进入下一轮,不会影响 else 的执行——只要循环最终是自然结束的(不是被 break 打断的),else 就会执行。可以把 else 理解为「循环没有被 break 打断时的庆祝动作」。

Q3: range(1000000) 会占用很多内存吗?

不会。Python 3 中的 range() 返回的是一个「惰性」序列对象,它只在需要时才计算下一个数字,内存占用极小(无论 range 多大,都只存储 start、stop、step 三个值)。这和 Python 2 中的 range()(返回一个完整的列表)完全不同。不过需要注意的是,如果写成 list(range(1000000)),那确实会创建一个包含 100 万个元素的列表并占用大量内存。

章节单词汇总

英文音标术语/释义
iteration/ˌɪtəˈreɪʃən/迭代;循环中的每一次重复执行
loop/luːp/循环;重复执行代码块的结构
traverse/trəˈvɜːrs/遍历;逐个访问集合中的每个元素
enumerate/ɪˈnjuːməreɪt/枚举;同时获取索引和值的遍历方式
iterate/ˈɪtəreɪt/迭代(动词);在循环中重复处理
range/reɪndʒ/范围;生成整数序列的内置函数
infinite/ˈɪnfɪnət/无限的;while True 会形成无限循环
sequence/ˈsiːkwəns/序列;有顺序的元素集合

面试练习

Q1 [单选] for i in range(5): print(i) 输出几个数字?

  • A. 6
  • B. 5
  • C. 4
  • D. 0
解答:range(5) 生成 0、1、2、3、4,共 5 个数字。注意 range(n) 从 0 开始,到 n-1 结束,不包含 n。

Q2 [单选] 以下代码的输出是?for i in range(1, 10, 3): print(i, end=" ")

  • A. 1 4 7 10
  • B. 1 4 7
  • C. 1 3 6 9
  • D. 1 2 3 4 5 6 7 8 9
解答:range(1, 10, 3) 从 1 开始,步长 3,到 10 之前结束:1、4、7。10 超出了 stop 值(不包含),所以输出 1 4 7

Q3 [多选] 关于 Python for 循环,以下哪些说法是正确的?

  • A. for 循环可以遍历字符串中的每个字符
  • B. for 循环可以遍历列表中的每个元素
  • C. for 循环只能遍历数字序列
  • D. for 循环配合 range() 可以控制循环次数
解答:C 错误——for 循环可以遍历任何可迭代对象(字符串、列表、元组、字典、集合、文件对象等)。字符串本质上是字符序列,所以 A 正确。

Q4 [单选] 以下哪个 while 循环不会变成死循环?

  • A. while True: print("A")
  • B. while 1: print("B")
  • C. x = 5; while x > 0: x -= 1
  • D. while "hello": print("D")
解答:C 中 x 初始为 5,每次循环减 1,当 x=0 时条件 x > 0 为 False,循环退出。A 和 B 的条件永远为 True(1 在 Python 中是 truthy),D 的 "hello" 是非空字符串,也是 truthy,都会死循环。

Q5 [单选] for item in [10, 20, 30]: print(item) 中,循环执行几次?

  • A. 3次
  • B. 2次
  • C. 30次
  • D. 1次
解答:列表有 3 个元素(10、20、30),for 循环遍历三次,每次 item 依次为 10、20、30。

Q6 [多选] 以下哪些场景适合使用 while 循环而非 for 循环?

  • A. 用户登录系统,输入错误密码可以重试直到正确
  • B. AI 模型训练直到验证损失不再下降
  • C. 遍历一个已知大小的列表求和
  • D. 游戏主循环,持续运行直到玩家退出
解答:A(不知道用户会输错几次)、B(不知道需要多少 epoch)、D(不知道游戏会持续多久)都适合 while。C 适合 for——列表大小已知,直接遍历即可。

Q7 [单选] 以下代码输出什么?for i in range(3): print(i) if i == 1: break else: print("完成")

  • A. 0 1 2 完成
  • B. 0 1
  • C. 0 1
  • D. 0 1 2
解答:range(3) 遍历 i=0、1、2。i=0 时打印 0;i=1 时打印 1 并执行 break 跳出循环。因为循环被 break 打断(非正常结束),所以 else 块不执行。最终输出 0 1。注意:实际代码中 else 需要正确的缩进对齐。

Q8 [单选] while True: 循环要如何安全退出?

  • A. 等待程序崩溃
  • B. 在循环体内使用 break 语句配合条件判断
  • C. 按 Ctrl+C 是唯一的方法
  • D. 循环会自动在 1000 次后退出
解答:while True 是故意写的死循环,必须靠循环体内的 break 配合条件判断来退出。比如 while True: 处理数据; if 数据为空: break。Ctrl+C 也能终止但那是外部强制中断,不是程序的正常退出机制。

Q9 [多选] 关于 enumerate() 函数,以下哪些是正确的?

  • A. enumerate(["a", "b"]) 产生 (0, "a")、(1, "b")
  • B. 可以通过 start 参数指定起始索引
  • C. enumerate() 只能用于列表
  • D. 常用于需要同时知道元素位置和值的场景
解答:A 正确,默认从 0 开始。B 正确,enumerate(lst, start=1) 从 1 开始。C 错误,enumerate 可用于任何可迭代对象。D 正确,在跟踪训练步数时非常实用。

Q10 [单选] 循环的 else 子句在什么情况下不会执行?

  • A. 循环正常完成所有迭代
  • B. 循环被 break 提前终止
  • C. 循环体中没有 break 语句
  • D. 循环体中有 continue 语句
解答:else 不会执行的唯一情况是循环被 break 提前终止。如果循环自然结束(遍历完所有元素,或 while 条件变为 False),else 都会执行。continue 只跳过当前迭代的剩余部分,不影响 else。