控制流——if、for、while 与可迭代对象

个人主页: > for_ever_love__ < (欢迎各位大佬莅临😊)
其他栏目: > 我想学python了 <

其他栏目: > iOS项目总结大全 <

其他栏目: > iOS UI <

文章目录

  • [控制流------if、for、while 与可迭代对象](#控制流——if、for、while 与可迭代对象)

控制流------if、for、while 与可迭代对象

承上:上一篇《容器类型全家桶》我们学会了用四种容器装数据。

本篇:本篇用 if、for、while 和可迭代对象让数据动起来------遍历语料、按条件过滤、控制训练流程。

启下:下一篇《函数------参数、lambda、*args 与作用域》把重复出现的循环逻辑封装成可复用单元。

学完这一节,你能动手做:

  1. 写出带早停(early stopping)和日志打印的训练循环骨架
  2. 用 enumerate、zip 和生成器遍历大规模语料而不撑爆内存
  3. 用 break/continue/for-else 写出清晰的条件分支

上一篇我们用容器把数据装好了,这一篇让代码"动起来"------控制流 。为什么它重要?因为大模型里最核心的几段逻辑,本质都是控制流:训练循环 (for epoch)、早停 (if + break)、数据过滤 (if)、生成直到结束符(while)。把控制流写顺,你就能读懂甚至写出训练脚本的主干。

一、if / elif / else:做判断

python 复制代码
loss = 0.023

if loss < 0.01:
    print("收敛得很好,可以停了")
elif loss < 0.1:
    print("还在下降,继续训练")
else:
    print("loss 太高,检查数据或学习率")

注意 Python 用缩进(通常 4 个空格)划分代码块,不用大括号。缩进错了逻辑就错了,这是新手最常见的编译期错误。

真值测试:空容器是"假"

python 复制代码
if not []:
    print("空列表是假")          # 会执行
if not "":
    print("空字符串是假")         # 会执行
if 0:
    print("0 是假")              # 不会执行
if "0":
    print("非空字符串'0'是真")    # 会执行!注意和数字 0 的区别

记住:空容器 [] {} () ""、数字 0、None 都是假 ,其余为真。这个特性让判断写得很简洁,但也要小心 0 和 "0" 的区别。

二、for 循环:遍历序列

python 复制代码
epochs = [1, 2, 3]
for e in epochs:
    print(f"第 {e} 轮训练")

三个高频搭档:

python 复制代码
words = ["我", "爱", "大模型"]

# enumerate:同时拿到下标和值
for i, w in enumerate(words):
    print(i, w)          # 0 我 / 1 爱 / 2 大模型

# range:生成数字序列
for step in range(0, 100, 10):    # 从 0 到 100(不含),步长 10
    print(step)

# zip:同时遍历两个列表
questions = ["Q1", "Q2"]
answers = ["A1", "A2"]
for q, a in zip(questions, answers):
    print(f"{q} -> {a}")

三、while 与 break / continue / else

while 在条件为真时一直循环,适合"不知道要循环多少次"的场景:

python 复制代码
# 生成式任务:一直生成,直到遇到结束符或达到最大长度
generated = []
max_len = 20
while len(generated) < max_len:
    token = "下一个词"          # 假装模型输出
    if token == "<EOS>":
        break                  # 遇到结束符,跳出循环
    generated.append(token)
else:
    print("循环正常结束(没触发 break)")
  • break:直接跳出整个循环;
  • continue:跳过本次,进入下一轮;
  • for/while ... else:循环没有被 break 中断时才执行 else(这个语法很冷门但有用)。

四、可迭代对象:for 背后到底在干什么

你之所以能 for x in 列表,是因为列表是可迭代对象 。它背后其实做了两件事:拿到迭代器 → 反复 next()。

python 复制代码
words = ["我", "爱", "大模型"]
it = iter(words)          # 拿到迭代器
print(next(it))           # 我
print(next(it))           # 爱
print(next(it))           # 大模型
# print(next(it))         # 抛 StopIteration,for 循环就是靠它结束的

理解这一点,后面读 enumerate、zip、生成器(yield)就不会懵------它们本质上都是"可迭代对象"。

五、实战:一个带早停的训练循环

把控制流串起来,写一个真实感很强的训练主干(不依赖任何深度学习库,用假数据模拟):

python 复制代码
import random

random.seed(42)
loss = 2.5                      # 初始 loss
best_loss = float("inf")        # 记录历史最好
patience = 3                    # 连续 3 轮不改善就停
no_improve = 0

for epoch in range(1, 21):      # 最多训 20 轮
    # 模拟每轮 loss 下降(带一点随机波动)
    loss = loss * 0.85 + random.uniform(-0.02, 0.02)

    print(f"epoch {epoch:2d} | loss = {loss:.4f}")

    # 判断是否有改善
    if loss < best_loss - 1e-4:
        best_loss = loss
        no_improve = 0
        print(f"  ✔ 有改善,保存模型(best={best_loss:.4f})")
    else:
        no_improve += 1
        print(f"  ✘ 无改善({no_improve}/{patience})")

    # 早停
    if no_improve >= patience:
        print(f"连续 {patience} 轮无改善,提前停止训练")
        break
else:
    print("20 轮全部跑完")

print(f"最终 best loss = {best_loss:.4f}")

运行结果示例:

复制代码
epoch  1 | loss = 2.1274
  ✔ 有改善,保存模型(best=2.1274)
epoch  2 | loss = 1.8069
  ✔ 有改善,保存模型(best=1.8069)
...
epoch  8 | loss = 0.6532
  ✘ 无改善(1/3)
epoch  9 | loss = 0.6610
  ✘ 无改善(2/3)
epoch 10 | loss = 0.6498
  ✘ 无改善(3/3)
连续 3 轮无改善,提前停止训练
最终 best loss = 0.6512

这段代码包含了真实训练脚本的全部控制流骨架:固定轮次的 for 、判断改善的 if 、计数与早停的 break 、兜底的 else 。以后你看到 PyTorch 的训练循环,会发现结构完全一样,只是把"假 loss"换成了真实的 loss.backward()。

六、常见坑与注意事项

坑 现象 解决办法
缩进不一致 IndentationError 或逻辑错乱 统一 4 空格,别混用 Tab
遍历时修改容器 漏元素或无限循环 遍历副本 lst[:],或用推导式
range 边界 range(1,10) 不含 10 记住"左闭右开"
while 死循环 程序卡死不退出 确保条件会变化,或加最大次数保护
用 == 判断 None 判断失效 用 is None / is not None
浮点数做循环条件 精度误差导致多跑/少跑一轮 用整数计数,或用容差

两个重点提醒:

  1. range(n) 不含 n :range(1, 10) 是 1~9。这是"左闭右开"惯例,和切片一致,习惯就好。
  2. while 一定要有出口 :循环体里必须让条件朝"假"的方向变化,否则死循环。稳妥做法是加一个 max_steps 上限(像上面 range(1, 21) 那样)。

七、for 与 while 怎么选

场景 推荐 原因
遍历已知序列(列表、range) for 简洁,自动处理结束
轮次固定的训练 for epoch in range(n) 轮数明确
次数未知,满足条件就停 while 如"生成到 EOS"
需要下标 for i, x in enumerate(...) 比 range(len()) 优雅
同时遍历多个序列 zip 自动对齐长度

口诀:能数得清用 for,数不清用 while。

八、本篇小结

  1. if/elif/else 靠缩进 分块;空容器、0、None 都是"假"。
  2. for 配 enumerate(带下标)、range(数字序列)、zip(并行遍历)是三大高频用法。
  3. while 适合次数未知的循环,break 跳出、continue 跳过、else 在未 break 时执行。
  4. 可迭代对象背后是 iter() + next(),这是理解生成器和迭代器的钥匙。
  5. 我们用控制流搭出了带早停的完整训练循环骨架------真实 PyTorch 脚本的主干结构一模一样。

下一篇讲函数 ------参数、lambda、*args/**kwargs 与作用域。你会学到怎么把重复逻辑封装成可复用的工具,这也是写出整洁大模型代码的关键一步。

本篇是《大模型开发从 0 到 1》专栏第 5 篇。专栏文章按「分类专栏」归类,顺序学习体验最佳。

相关推荐
for_ever_love__1 小时前
PyTorch 张量与 autograd——自动求导怎么工作
pytorch·python·深度学习·自动求导
小小张说故事1 小时前
Python 里 `is` 和 `==` 到底差在哪?5 个让你怀疑人生的案例 + 对照表
python
XLYcmy2 小时前
PDF 论文处理器 — 改进方向与建议文档
python·pdf·llm·agent·dify·rag·harness
青柠之夏cc2 小时前
前端拖拽功能原生实现,不引入拖拽库完成业务
开发语言·前端·python
曾晓森2 小时前
OpenAI 兼容 API 接入山猫云:先核对分组和价格,再发最小请求
网络·python
OKkankan2 小时前
Python 高阶语法(一):高阶函数、闭包、lambda 与 functools——从底层真正理解装饰器
开发语言·python
智鸟科技GemeOpen开发者智能设备3 小时前
平安校园 AI 智能实时告警系统 智鸟科技·GemeOpen + 谷华科技·融合创新方案白皮书
java·开发语言·python·物联网·智能家居
Sand(ContextGate)3 小时前
Python Agent 测试实战:测试与评估,让 Agent 像传统软件一样可交付
前端·javascript·python·microsoft·ai
空心木偶☜4 小时前
LangChain 概述
python·ai·langchain·ai编程