Python 生成器函数详解

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

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

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


目录

  1. 什么是生成器函数?
  2. 普通函数 vs 生成器函数
  3. yield 是啥?怎么用?
  4. 用 for 遍历生成器函数
  5. yield 与 return 的区别
  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. yield 与 return 的区别

对比点 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. 注意事项与陷阱

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

10. 小结和写法建议

🔑 关键词记牢:

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

✅ 什么时候用生成器函数?

  • 数据太大不能一次加载
  • 想要按需生成值(比如实时日志、数据流)
  • 想写更优雅的代码逻辑,减少临时变量
相关推荐
高级程序源5 小时前
django校园寻物通失物招领平台32261-计算机课程设计、毕业设计
vue.js·python·mysql·小程序·django·flask·课程设计
WeiXin_DZbishe5 小时前
基于springboot宠物领养系统-计算机毕设 附源码【课程设计】94217
vue.js·spring boot·python·django·php·课程设计
kimnoic5 小时前
Python数据库学习心得:SQLite、MySQL、PostgreSQL优缺点
开发语言·python
snhna5 小时前
向量数据库深度实战:从 HNSW 到 pgvector、Milvus 选型与 RAG 落地
数据库·人工智能·python·postgresql·milvus
必须得开心呀6 小时前
python编写带界面的软件,需要安装哪些插件
开发语言·python
Wx-bishekaifayuan6 小时前
express皖美特色农产品网售系统53118-计算机课程设计、毕业设计
人工智能·spring boot·后端·python·课程设计·express·旅游
青少儿编程课堂7 小时前
迪杰斯特拉(Dijkstra)算法:单源最短路与赛场路线规划
c++·python·算法·bfs·信息学竞赛
计算机编程指导师7 小时前
【计算机毕设推荐】基于Hadoop+Spark的公共交通运营数据分析与可视化系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·计算机·数据分析·spark·交通
Wx-bishekaifayuan7 小时前
springboot汉中旅游服务平台41442-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游
WeiXin_DZbishe7 小时前
基于springboot城市公交实时运营与调度系统-计算机毕设 附源码【课程设计】66173
java·vue.js·spring boot·后端·python·php·课程设计