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 简化嵌套
  • 生成器 = 惰性计算 + 节省内存 + 逻辑清晰

什么时候用生成器函数?

  • 数据太大不能一次加载
  • 想要按需生成值(比如实时日志、数据流)
  • 想写更优雅的代码逻辑,减少临时变量
相关推荐
XLYcmy13 小时前
京东 算法实习一面 下+手撕
c++·python·llm·概率论·数据处理·训练·codebert
虎头金猫13 小时前
如何在群晖NAS上通过Docker部署CloudSaver?群晖部署CloudSaver教程|聚合资源搜索并实现远程访问
运维·服务器·网络·python·docker·容器·pandas
从零开始学习人工智能14 小时前
WSL2部署CUDA12+cuDNN9踩坑实录:ONNX Runtime GPU推理环境搭建全流程
python
m0_3807438714 小时前
从零调用 Claude 教程
开发语言·python·node.js
min(a,b)15 小时前
学习第17天:Agent Memory 与 MCP 协议
python·学习
CodeBlog-star16 小时前
LLM安全实战:提示词注入与越狱攻击防御指南
python·agent·提示词攻击·越狱攻击
小柯南敲键盘16 小时前
电商图片翻译工具推荐,批量处理主图视频字幕,免费试用
大数据·人工智能·python·音视频
比高创意品牌策划设计17 小时前
零售卖场设计软件用CAD还是SketchUp还是酷家乐
python
迷迭香yy18 小时前
行业板块轮动因子实战从板块资金到因子建模的本地化Python全流程
数据库·人工智能·python
W_3260018 小时前
Python文件进阶:一维数据与 CSV 文件读写
开发语言·python