Python中yield的用法详解——最简单,最清晰的解释 | 生成器/面试必看(2026版)

Python中 yield 的用法详解 —— 2026年最简单、最清晰的版本

yield 是 Python 中最神奇、最有价值的关键词之一。
它让一个普通函数秒变生成器(generator),带来内存节省 + 惰性计算 + 状态保持三大超级能力。

下面用最直白的语言 + 递进式例子帮你彻底搞懂(面试/日常开发都够用)。

1. 最核心的一句话理解 yield

return 改成 yield,函数就从“一次性把所有结果算完再给你”
变成了“算一个给你一个,暂停在那等你下次再来要”

# 普通函数(一次性返回所有)
def odds(n):
    result = []
    for i in range(n):
        if i % 2 == 1:
            result.append(i)
    return result

# 用 yield 改写 → 生成器
def odds_gen(n):
    for i in range(n):
        if i % 2 == 1:
            yield i          # 每次只产生一个,暂停

使用对比:

print(odds(10))          # [1,3,5,7,9]  — 一次性全在内存

g = odds_gen(10)
print(list(g))           # [1,3,5,7,9]  — 但中间只在内存中存在一个数

内存杀手级差异:当 n=1亿 时,列表版会吃爆内存,生成器版几乎不占额外内存。

2. yield 到底做了什么?(执行流程图解)

def simple_gen():
    print("开始")
    yield 100
    print("又回来了")
    yield 200
    print("结束了")
    # 没有更多 yield 了,自动 raise StopIteration

g = simple_gen()          # 调用函数 → 并不执行函数体,只得到一个生成器对象

print(next(g))            # → "开始" 被打印 → 输出 100 → 暂停在 yield 100 后面
print(next(g))            # → "又回来了" 被打印 → 输出 200 → 暂停
# print(next(g))          # → "结束了" 被打印 → 抛出 StopIteration

一句话总结执行顺序:

  1. 调用函数 → 返回生成器对象(不执行函数体
  2. 第一次 next()for → 从头执行到第一个 yield → 返回 yield 的值 → 暂停
  3. 第二次 next() → 从上次暂停处继续 → 到下一个 yield → 返回值 → 暂停
  4. 没有更多 yield → 抛 StopIteration(for 循环会自动处理)

3. 最常用的三种写法(记住这三种就够 90% 场景)

写法1:最基础版(产生序列)

def fib(n):
    a, b = 0, 1
    while a < n:
        yield a
        a, b = b, a + b

for x in fib(100):
    print(x, end=' ')     # 0 1 1 2 3 5 8 13 ...

写法2:yield + 列表推导式(最优雅)

# 普通列表推导式(占内存)
squares = [x*x for x in range(10000000)]

# 生成器表达式(几乎不占内存)
squares_gen = (x*x for x in range(10000000))

print(next(squares_gen))   # 0
print(next(squares_gen))   # 1

写法3:yield from(委托给另一个可迭代对象) —— Python 3.3+ 引入,超级实用

def chain():
    yield from [1, 2, 3]
    yield from range(5, 8)
    yield from "abc"

print(list(chain()))  
# [1,2,3,5,6,7,'a','b','c']

等价于(但更清晰):

def chain_old():
    for x in [1,2,3]:     yield x
    for x in range(5,8):  yield x
    for x in "abc":       yield x

4. 进阶但很常用的:生成器可以接收值(.send())

def talker():
    while True:
        cmd = yield               # yield 出现在 = 右边 → 可以接收值
        print(f"收到指令:{cmd}")

g = talker()
next(g)             # 必须先启动到第一个 yield(重要!)

g.send("开灯")     # 收到指令:开灯
g.send("关门")     # 收到指令:关门

经典协程风格写法(早期协程就是这么玩的):

def accumulator():
    total = 0
    while True:
        value = yield total     # 接收值 → 赋值给 value
        total += value or 0

acc = accumulator()
next(acc)                   # 启动 → 得到 0
print(acc.send(10))         # 10
print(acc.send(30))         # 40
print(acc.send(5))          # 45

5. 面试/工作中最常被问的 8 个点(2026版)

排名问题核心回答一句话
1yield 和 return 区别?return 结束函数并返回值;yield 返回值+暂停函数,下次可继续执行
2生成器和迭代器区别?生成器一定是迭代器,但迭代器不一定是生成器(生成器是用 yield 函数实现的迭代器)
3第一次调用生成器函数发生了什么?什么都没执行,只返回了一个生成器对象
4怎么启动生成器?next(g) 或 for 循环(for 会自动处理 StopIteration)
5yield from 有什么用?委托给另一个可迭代对象,简化多层 yield,自动处理子生成器的返回值
6生成器可以用多次吗?不可以,耗尽后就废了(除非重新生成一个)
7生成器表达式和列表推导式区别?() 是生成器,[] 是列表;前者惰性,后者立即计算
8什么时候用 yield 而不是 return?需要惰性计算、节省内存、处理大数据流、实现协程/管道、需要中途暂停恢复时

6. 2026年一句话总结(送给未来的你)

yield 是 Python 送给程序员的“时间暂停器 + 内存魔法棒”
用它,你可以写出“看起来像列表,用起来像流”的优雅代码。

记住这个最简心法:

  • 想一次性全算完 → 用 return + 列表
  • 想边算边用、内存友好 → 用 yield + 生成器
  • 想委托给别人 → 用 yield from

需要我再给你出 5 道 yield 面试真题带答案吗?或者想看某个具体场景的完整代码?直接说~

文章已创建 4862

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部