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

什么时候用生成器函数?

  • 数据太大不能一次加载
  • 想要按需生成值(比如实时日志、数据流)
  • 想写更优雅的代码逻辑,减少临时变量
相关推荐
中等生1 小时前
Python的隐形枷锁:GIL如何"绑架"了你的多线程梦想
后端·python
电商数据girl1 小时前
关于私域电商网站,接入电商API数据接口示例
运维·开发语言·网络·python·json·php
Ly2020Wj2 小时前
pytorch入门3:使用pytorch进行多输出手写数据集模型预测
人工智能·pytorch·python
码界筑梦坊2 小时前
90-基于Flask的中国博物馆数据可视化分析系统
python·信息可视化·flask
七七软件开发2 小时前
无人共享 app 系统架构分析
java·python·小程序·系统架构·php
WaterRun2 小时前
一个极简极易用, "即读即用"的Python存储库介绍: SimpSave
python
WaterRun2 小时前
使用Python合并B站缓存视频(至.MP4): 库biliffm4s介绍
python
gonghw4032 小时前
Python中变量之间赋值的理解
python
疯狂的Alex2 小时前
未来20年哪几种编程语言会保持优势?哪几种编程语言会得到更广泛的应用?
java·开发语言·c++·python·c#