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

什么时候用生成器函数?

  • 数据太大不能一次加载
  • 想要按需生成值(比如实时日志、数据流)
  • 想写更优雅的代码逻辑,减少临时变量
相关推荐
风送雨4 分钟前
八周Python强化计划(七)
开发语言·python
ππ很开心6667 分钟前
DAY 32 函数专题2:装饰器
开发语言·python
山沐与山21 分钟前
LangChain Tools解析:让Agent拥有超能力
人工智能·python·langchain
TonyLee01723 分钟前
python代码运行时间信息记录
python
曲幽28 分钟前
手把手搞定FastAPI静态文件:安全、上传与访问
css·python·fastapi·web·js·favicon·staticfiles
sandwu29 分钟前
AI Agent——可观测性链路集成&评测体系搭建(Langfuse)
人工智能·python·langchain·langfuse
未来之窗软件服务36 分钟前
幽冥大陆(八十四)Python 水果识别PTH 转 ONNX 脚本新 —东方仙盟练气期
人工智能·python·深度学习·仙盟创梦ide·东方仙盟·阿雪技术观
XLYcmy41 分钟前
高级密码生成器程序详解:专门设计用于生成基于用户个人信息的密码猜测组合
开发语言·数据结构·python·网络安全·数据安全·源代码·口令安全
阿豪只会阿巴1 小时前
【多喝热水系列】从零开始的ROS2之旅——Day4
c++·笔记·python·ros2
2401_841495641 小时前
【LeetCode刷题】寻找重复数
数据结构·python·算法·leetcode·链表·数组·重复数