DevCN
菜单
全部文章快讯开发科技深度热点

Python 生成器:按需清洗学习记录并理解一次性迭代

用生成器逐条清洗文本记录,观察 yield、next 与列表转换的消费过程,避免把已经耗尽的迭代器当成可反复使用的数据列表。


本节目标

用生成器逐条清洗文本记录,观察 yield、next 与列表转换的消费过程,避免把已经耗尽的迭代器当成可反复使用的数据列表。

知识与使用场景

如果一批数据只需要逐条处理,不一定先建立一个包含所有清洗结果的列表。生成器函数在运行到 yield 时交出一个值,并保留当前位置,下次请求时继续执行。

本节过滤空行和注释行,再把有效记录转成整数。它选择严格失败策略:格式错误直接抛异常,不悄悄丢弃;负数也会报告错误。输入是演示列表,但同样的迭代方式可以接收文件对象逐行提供的数据。

生成器自身不会缓存已经交出的值。next 取出第一条后,再用 list 收集,只能得到剩余部分。若后续工作需要反复遍历,应该重新创建生成器,或明确将全部结果保存成列表。

完整示例

def valid_minutes(lines):
    for line in lines:
        text = line.strip()
        if not text or text.startswith("#"):
            continue
        value = int(text)
        if value < 0:
            raise ValueError("时长不能为负数")
        yield value


source = [" 20 ", "", "# 休息日备注", "35", "0"]
stream = valid_minutes(source)
print(next(stream))
print(list(stream))
print(list(stream))
print(sum(valid_minutes(source)))

预期结果

20
[35, 0]
[]
55

运行与逐步理解

第一行 next 驱动函数开始处理,在遇到 20 时暂停。之后 list 继续请求值,空行和注释被跳过,得到 35 和 0。再次转换同一个 stream 时已经没有剩余元素,因此是空列表。

最后一行重新调用 valid_minutes,创建一个新的生成器,从头统计得到 55。若错误地对已经耗尽的 stream 求和,将得到 0。这类问题很容易隐藏在先打印调试、后进行计算的代码里。

延迟执行也意味着错误可能发生在消费阶段。仅把 stream = valid_minutes(source) 放在 try 中,通常捕获不到后面迭代时的格式错误;需要围住实际的 next、for 或 list 操作。

常见问题与边界

  • 生成器没有列表那样的通用随机索引,不应直接使用 stream[0]。
  • 如果输入本身已经是巨大列表,生成器只减少中间结果占用,不会让原列表消失。
  • 空输入的 next 会抛 StopIteration;可以使用 next(stream, None) 给出默认值。
  • 文件逐行生成器必须在文件仍打开时消费,不能把关闭后的文件留给后续读取。

动手练习

对空列表创建生成器,使用带默认值的 next;再把输入改为 ["20", "错误"],观察异常何时发生。

参考答案

next(valid_minutes([]), None) 返回 None。第二组第一次 next 返回 20,第二次请求结果时 int 转换才抛 ValueError。创建生成器对象这一行并没有提前完成数据校验。

DISCUSSION

文章回复

0 条公开回复
未登录回复需要审核后公开
还没有回复,欢迎参与讨论。