Python: 迭代器与生成器

最后更新:2026-09-22

你已经在用 for x in list: 遍历数据了,但有没有想过 in 后面可以跟哪些东西?range(1000000) 为什么不占内存?迭代器和生成器就是答案。它们让你能处理"无限"的数据流——按需生成,不占内存。


相关内置函数:reversed() iter() next() return yield for

1. 什么是迭代器协议

Python 中,任何可以被 for 循环遍历的对象都可迭代(iterable)。它们背后实现了迭代器协议:

▶ 示例:迭代器协议基础

▶ 试一试

输出:

TEXT 📖 仅展示
# 执行成功

for 循环本质上就是:

▶ 示例:手动模拟 for 循环

▶ 试一试

输出:

TEXT 📖 仅展示
# 执行成功


2. 自定义迭代器

实现 __iter__ 和 __next__ 方法,让你的类能用 for 遍历:

▶ 示例:倒计时迭代器

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功

▶ 示例:斐波那契迭代器(难度⭐⭐)

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功


3. 生成器:yield

写一个类实现 __iter__ 和 __next__ 挺麻烦的。生成器函数用 yield 就能搞定同样的事:

▶ 示例:倒计时生成器

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功

yield 和 return 不同——return 结束函数,而 yield 暂停函数,记住当前状态,下次调用时从暂停处继续。

▶ 示例:斐波那契生成器

▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功
💡 生成器 vs 迭代器类: 生成器函数(yield)通常比手写迭代器类简洁得多。绝大多数场景下,生成器是首选。只有需要维护复杂状态或需要额外方法时,才考虑手写迭代器类。



4. 生成器的懒加载特性

生成器最大的优势是——不一次性生成所有数据,按需生产:

▶ 示例:生成器懒加载

▶ 试一试

输出:

TEXT 📖 仅展示
生成 1
生成 2
生成 3
创建了生成器,但还没执行

看到执行过程了吧?每次 next() 才执行到下一个 yield,然后停住。这个特性在处理大数据时非常有用:

▶ 示例:逐行读取大文件

TEXT 📖 仅展示
# 处理大文件的"懒加载"方式
def read_large_file(filename):
    """逐行读取大文件,不一次性加载到内存"""
    with open(filename, "r", encoding="utf-8") as f:
        for line in f:
            yield line.strip()

# 用生成器处理——每次只处理一行
for line in read_large_file("huge_log.txt"):
    if "ERROR" in line:
        print(line)  # 处理速度只受磁盘读取速度限制


5. 生成器表达式

和列表推导式很像,但用圆括号——生成器表达式是惰性求值的:

▶ 示例:生成器表达式

▶ 试一试

输出:

TEXT 📖 仅展示
# 执行成功
对比 列表推导式 [] 生成器表达式 ()
内存 所有数据在内存中 按需生成,几乎不占
速度 生成快,后续访问快 生成惰性,每次计算
可复用 可以反复遍历 只能遍历一次
适用场景 数据量小、需要反复使用 数据量大、只需遍历一次
💡 什么时候用生成器? ① 数据量大(几千条以上)。② 只需遍历一次。③ 需要流式处理(逐行读文件、实时数据流)。④ 想表达"无限序列"的概念。"



6. 常见应用场景


相关内置函数:reversed() iter() next() return yield for

❓ 常见问题

Q 生成器和普通函数有什么区别?
A 普通函数用 return 一次性返回结果,函数结束。生成器用 yield 逐个产生值,每次暂停保存状态,下次从暂停处继续。生成器函数每次调用返回一个新的生成器对象。
Q 生成器只能遍历一次,想反复遍历怎么办?
A 用 list(gen) 把生成器转成列表。但如果数据量太大,转列表会耗尽内存。折中方案:用 itertools.tee() 复制生成器,或者重新调用生成器函数生成一个新的。
Q yield 和 return 可以共存吗?
A 可以——return 在生成器中相当于"停止迭代"并返回 StopIteration 的值。不过很少这么用。实践中如果你发现一个函数既要 yield 又要 return,最好想想设计是否合理。

📖 小节


📝 作业

  1. 基础题(难度⭐):用生成器写一个 even_numbers(max_n) 函数,生成从 0 到 max_n 之间的所有偶数。

  2. 进阶题(难度⭐⭐):用生成器写一个 repeat_list(items, times) 函数,把列表中的每个元素重复 times 次。例如 list(repeat_list([1, 2, 3], 2)) 返回 [1, 1, 2, 2, 3, 3]。

  3. 挑战题(难度⭐⭐⭐):写一个生成器 deep_flatten(nested),可以展开任意深度的嵌套列表。例如 list(deep_flatten([1, [2, [3, 4]], 5])) 返回 [1, 2, 3, 4, 5]。提示:用 for 遍历元素,如果元素是列表则递归调用 yield from。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏