Python 生成器函数详解

在 Python 中,有一种非常神奇的函数:生成器函数(Generator Function) 。它既像函数,又像一个"能记住中间状态"的魔法盒子,处理大数据流时特别好用!

本篇文章会一步一步带你搞懂生成器函数到底是个啥,有啥用,怎么写,怎么用。

参考文章:Python 迭代器 | 简单一点学习 easyeasy.me


目录

  1. 什么是生成器函数?
  2. 普通函数 vs 生成器函数
  3. yield 是啥?怎么用?
  4. for 遍历生成器函数
  5. yieldreturn 的区别
  6. next() 手动调用生成器
  7. yield from:更优雅地嵌套生成器
  8. 生成器函数的应用场景
  9. 注意事项与陷阱
  10. 小结和写法建议

1. 什么是生成器函数?

生成器函数,就是一种yield 而不是 return 返回值的函数 。它的作用是:每次调用返回一个值,但不会退出函数,而是暂停在当前位置,下一次继续从暂停处执行。

举个栗子:

python 复制代码
def my_gen():
    yield 1
    yield 2
    yield 3

调用这个函数时,它不会立马执行,而是返回一个生成器对象:

python 复制代码
g = my_gen()
print(g)  # <generator object my_gen at ...>

2. 普通函数 vs 生成器函数

特性 普通函数 生成器函数
使用关键字 return yield
返回什么 一次性返回所有结果 每次返回一个值
内存消耗 可能较大 非常省内存
可暂停执行 ❌ 不可以 ✅ 可以暂停并恢复执行

3. yield 是啥?怎么用?

yield 是生成器函数的灵魂。它会把函数暂停,把值"送"出去,并等待下一次调用。

python 复制代码
def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1

用法:

python 复制代码
for num in count_up_to(3):
    print(num)

输出:

python 复制代码
1
2
3

每次 yield 一个值,下一轮从 yield 的下一行接着运行。


4. 用 for 遍历生成器函数

这是最常见的用法。其实背后是迭代器的原理(用 next() 一点点去取),但你不用管这些,只管像遍历列表一样用就行:

python 复制代码
def gen_words():
    yield "hello"
    yield "world"

for word in gen_words():
    print(word)

输出:

python 复制代码
hello
world

5. yieldreturn 的区别

对比点 yield return
暂停函数 ✅ 是 ❌ 否(直接结束函数)
返回值 一次一个 一次性全部
多次调用 每次从上次 yield 后继续 每次都重新开始

例子对比:

python 复制代码
def func_return():
    return 1
    return 2  # 永远不会执行

def func_yield():
    yield 1
    yield 2

6. 用 next() 手动调用生成器

可以不用 for,直接用 next() 来一个一个取值:

python 复制代码
g = (x * 2 for x in range(3))
print(next(g))  # 0
print(next(g))  # 2
print(next(g))  # 4
# print(next(g))  # StopIteration

对生成器函数也是一样:

python 复制代码
def simple_gen():
    yield "A"
    yield "B"

g = simple_gen()
print(next(g))  # A
print(next(g))  # B

7. yield from:更优雅地嵌套生成器

如果你要在一个生成器中调用另一个生成器,可以用 yield from 代替一大堆 for 循环。

传统写法:

python 复制代码
def outer():
    for val in [1, 2, 3]:
        yield val

更简洁写法:

python 复制代码
def outer():
    yield from [1, 2, 3]

也支持嵌套生成器函数:

python 复制代码
def gen1():
    yield "A"
    yield "B"

def gen2():
    yield from gen1()
    yield "C"

for x in gen2():
    print(x)

输出:

python 复制代码
A
B
C

8. 生成器函数的应用场景

生成器函数在处理大量数据流式数据时非常好用:

📄 场景1:按行读取大文件

python 复制代码
def read_large_file(path):
    with open(path, "r") as f:
        for line in f:
            yield line.strip()

🔢 场景2:无限序列(如斐波那契)

python 复制代码
def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b
scss 复制代码
f = fib()
for _ in range(10):
    print(next(f))

🎲 场景3:模拟数据流或日志流

python 复制代码
import time

def log_stream():
    count = 0
    while True:
        yield f"log line {count}"
        count += 1
        time.sleep(1)

9. 注意事项与陷阱

  • 🚫 生成器只能遍历一次,想再用得重新生成
  • 不能随便混用 yieldreturn,尤其是在同一个代码路径上
  • yield 后的函数不会立马执行,只有取值时才会跑
  • 📉 如果里面抛异常没处理,会导致整个生成器终止

10. 小结和写法建议

🔑 关键词记牢

  • yield 产生一个值,函数暂停
  • next() 继续执行生成器
  • yield from 简化嵌套
  • 生成器 = 惰性计算 + 节省内存 + 逻辑清晰

什么时候用生成器函数?

  • 数据太大不能一次加载
  • 想要按需生成值(比如实时日志、数据流)
  • 想写更优雅的代码逻辑,减少临时变量
相关推荐
计算机程序员小杨14 分钟前
计算机毕设选题:电子商务供应链大数据分析系统Python+Django技术实现详解|毕设|计算机毕设|程序开发|项目实战
java·vue.js·python
moxiaoran575315 分钟前
Django Admin 管理工具
python·django
小先生001011 小时前
GraphRAG 知识图谱核心升级:集成 langextract 与 Gemini ----实现高精度实体与关系抽取
人工智能·python·开源·prompt·github·bert·知识图谱
跟橙姐学代码2 小时前
写Python的人,都应该掌握的高效写法(用了真的爽!)
前端·python·ipython
阿豪在学习2 小时前
win环境使用pixi,安装vnpy(python3.13.5)
python
呲溜滑_3 小时前
electron-vite 配合python
javascript·python·electron
wei_shuo3 小时前
使用 Bright Data Web Scraper API + Python 高效抓取 Glassdoor 数据:从配置到结构化输出全流程实战
python·亮数据·bright data·web scraper api
Harvey663 小时前
Python 轻量级 HTML 解析器 - lxml入门教程
python·html·高性能·轻量级·html 解析器·框架lxml·简单爬虫
二向箔reverse3 小时前
OpenCV轮廓近似与Python命令行参数解析
人工智能·python·opencv
RickyWasYoung3 小时前
【python】相机输出图片时保留时间戳数据
python·数码相机·opencv