Python 生成器与迭代器:用惰性计算处理大数据流

举报
yd_269685704 发表于 2026/11/02 10:04:35 2026/11/02
【摘要】 一、为什么需要惰性计算处理日志文件、数据库游标或网络数据流时,一次性把全部数据读进列表往往既占内存又慢。生成器(generator)只在需要时才产生下一个值,用多少算多少,是 Python 里最实用的惰性计算工具。二、迭代器协议:iter 与 next迭代器是实现了 __iter__ 和 __next__ 的对象。iter() 返回迭代器自身,next() 取出下一个值,取完后抛出 Stop...

一、为什么需要惰性计算

处理日志文件、数据库游标或网络数据流时,一次性把全部数据读进列表往往既占内存又慢。生成器(generator)只在需要时才产生下一个值,用多少算多少,是 Python 里最实用的惰性计算工具。

二、迭代器协议:iter 与 next

迭代器是实现了 __iter__ 和 __next__ 的对象。iter() 返回迭代器自身,next() 取出下一个值,取完后抛出 StopIteration。for 循环正是不断调用 next() 直到异常为止的语法糖。

class Countdown:
    def __init__(self, n):
        self.n = n
    def __iter__(self):
        return self
    def __next__(self):
        if self.n <= 0:
            raise StopIteration
        self.n -= 1
        return self.n + 1
for x in Countdown(3):
    print(x)  # 3 2 1

三、生成器函数:yield 让函数“暂停”

含有 yield 的函数调用后并不执行,而是返回一个生成器;每次 next() 执行到 yield 就暂停并返回值,下次从断点继续,局部状态全部保留。

def read_lines(path):
    with open(path, encoding='utf-8') as f:
        for line in f:
            if line.strip():
                yield line.strip()
# 逐行处理 10GB 日志,内存占用始终只有一行
for line in read_lines('app.log'):
    if 'ERROR' in line:
        print(line)

四、生成器表达式:列表推导的惰性版

把列表推导的方括号换成圆括号,就得到生成器表达式,适合做流水线式处理:

total = sum(int(x) for x in open('nums.txt') if x.strip())
squares = (x * x for x in range(10 ** 8))  # 不占内存,随用随算

五、yield from:委托给子生成器

yield from 把子生成器的产出直接转发出去,还能透传 send() 的值与返回值,写递归遍历、树形展开时特别干净:

def walk(tree):
    yield tree['name']
    for child in tree.get('children', []):
        yield from walk(child)

六、常见坑

第一,生成器只能消费一次,第二次遍历会直接为空,需要重建或用 itertools.tee;第二,不要在生成器里过早关闭资源,with 语句要包在生成器函数内部,调用方只管迭代;第三,send()、throw()、close() 会改变生成器状态,调试时先确认执行到了哪个 yield。

一句话总结:列表是“先算好再给你”,生成器是“用到哪算到哪”。数据量越大、流水线越长,生成器的收益越明显。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。