Python 生成器基础:yield 核心原理

文章目录

    • 前言
    • 一、先搞懂:什么是生成器?为什么要用它?
      • [1.1 从一个最扎心的场景说起](#1.1 从一个最扎心的场景说起)
      • [1.2 生成器的官方定义(2026最新Python规范)](#1.2 生成器的官方定义(2026最新Python规范))
    • [二、yield 与 return 的本质区别:一句话戳穿](#二、yield 与 return 的本质区别:一句话戳穿)
      • [2.1 return:彻底结束,一去不返](#2.1 return:彻底结束,一去不返)
      • [2.2 yield:暂停执行,暂存状态](#2.2 yield:暂停执行,暂存状态)
    • 三、手写第一个生成器:从代码看执行流程
      • [3.1 最简单的生成器函数](#3.1 最简单的生成器函数)
      • [3.2 调用生成器函数并不会执行代码!](#3.2 调用生成器函数并不会执行代码!)
      • [3.3 一步步执行next()](#3.3 一步步执行next())
    • 四、生成器核心原理:底层到底发生了什么?
      • [4.1 生成器 = 函数 + 状态机](#4.1 生成器 = 函数 + 状态机)
      • [4.2 为什么生成器极省内存?](#4.2 为什么生成器极省内存?)
    • [五、生成器的两种写法:函数式 & 表达式式](#五、生成器的两种写法:函数式 & 表达式式)
      • [5.1 生成器函数(带yield的函数)](#5.1 生成器函数(带yield的函数))
      • [5.2 生成器表达式(2026最常用简写)](#5.2 生成器表达式(2026最常用简写))
    • 六、实战:生成器最常用的4大场景(2026最新实战)
      • [6.1 超大文件读取(必掌握)](#6.1 超大文件读取(必掌握))
      • [6.2 无限序列生成(不爆内存)](#6.2 无限序列生成(不爆内存))
      • [6.3 数据流水线/管道(Pythonic核心)](#6.3 数据流水线/管道(Pythonic核心))
      • [6.4 协程基础(asyncio核心前身)](#6.4 协程基础(asyncio核心前身))
    • 七、生成器高级特性:send、close、throw(2026面试高频)
      • [7.1 send():向生成器传值](#7.1 send():向生成器传值)
      • [7.2 close():手动关闭生成器](#7.2 close():手动关闭生成器)
      • [7.3 throw():向生成器抛异常](#7.3 throw():向生成器抛异常)
    • [八、yield from:2026必备简化语法](#八、yield from:2026必备简化语法)
      • [8.1 不用yield from的嵌套](#8.1 不用yield from的嵌套)
      • [8.2 用yield from极简写法](#8.2 用yield from极简写法)
    • 九、常见误区与避坑指南(2026实测)
      • [9.1 生成器只能迭代一次!](#9.1 生成器只能迭代一次!)
      • [9.2 不要在生成器里做耗时阻塞操作](#9.2 不要在生成器里做耗时阻塞操作)
      • [9.3 生成器不是线程安全](#9.3 生成器不是线程安全)
    • [十、总结:yield 核心原理一句话吃透](#十、总结:yield 核心原理一句话吃透)

P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看,传送门https://blog.csdn.net/HHX_01

前言

在Python开发领域,2026年的今天,生成器(Generator)早已不是什么小众高级语法,而是成为了Pythonic编程的核心基石之一。无论是日常数据处理、海量文件读取,还是异步编程、AI数据流水线,yield关键字都无处不在。但对于很多刚入门Python的小白,甚至有一两年开发经验的同学来说,yield始终像一层窗户纸------看着简单,一用就懵,到底它和普通return有啥区别?生成器凭什么能省内存?迭代的时候到底发生了什么?

这篇文章就用最通俗的段子+类比,从零拆解Python生成器的核心原理,全程基于Python 3.12+最新特性,2026年通用实战写法,不讲过时内容,不讲虚的,看完你能彻底吃透yield,写出更优雅、更高效的Python代码。

一、先搞懂:什么是生成器?为什么要用它?

1.1 从一个最扎心的场景说起

假设你现在要处理1亿条数据,可能是日志、用户行为、AI训练样本,你第一反应会怎么写?

大概率是这样:

python 复制代码
def get_big_data():
    data = []
    for i in range(100000000):
        data.append(i)
    return data

data_list = get_big_data()

跑一下你就会发现:内存直接炸了

因为这个函数会一次性把1亿个整数全部塞进列表,全部加载到内存里。你的电脑就算32G内存,也顶不住这种粗暴操作。

这就是普通函数 的痛点:一次性产出所有结果,占满内存

那生成器呢?

生成器的理念是:我不一次性给你全部,你要一个,我给你一个,用完再说下一个

就像奶茶店卖奶茶:

  • 普通函数:一次性做好1000杯,堆在店里,占满地方,你要喝自己拿。
  • 生成器:你点一杯,我做一杯,你喝完再点下一杯,店里永远只留一杯。

内存占用天差地别。

1.2 生成器的官方定义(2026最新Python规范)

根据Python 3.13官方文档定义:

生成器是一种简化的迭代器实现,使用yield关键字定义,可以暂停执行并保存当前执行状态,下次调用时从暂停处恢复执行。

翻译成人话:

  • 生成器本质是迭代器
  • yield暂停函数
  • 状态会被保存,下次接着跑
  • 不一次性生成所有数据

这就是生成器的核心价值:惰性计算(Lazy Evaluation),用到才计算,极大节省内存。

在2026年AI大模型数据处理、流式数据传输、高并发后端开发中,生成器是标配技能,不会yield,基本写不出高性能Python代码。

二、yield 与 return 的本质区别:一句话戳穿

很多小白最大的困惑:yield不就是return吗?为什么还要多一个关键字?

大错特错!

2.1 return:彻底结束,一去不返

普通函数遇到return

  1. 返回值
  2. 函数彻底结束
  3. 局部变量全部销毁
  4. 下次调用从头再来

就像射箭:箭射出去,弓就空了,想再射必须重新搭箭。

2.2 yield:暂停执行,暂存状态

生成器函数遇到yield

  1. 返回值
  2. 函数暂停执行,不结束
  3. 保存当前所有变量、执行位置、栈状态
  4. 下次调用next()时,从yield下一行继续执行

就像游戏机存档:打到boss存个档,下次开机直接从boss开打,不用从头打。

这就是两者最本质的区别:return是终结,yield是暂停

三、手写第一个生成器:从代码看执行流程

我们用最简单的代码,一步步看yield到底怎么跑。

3.1 最简单的生成器函数

python 复制代码
def simple_generator():
    print("第一步:开始执行")
    yield 1
    print("第二步:恢复执行")
    yield 2
    print("第三步:最后执行")
    yield 3

注意:这不是普通函数,这是生成器函数

3.2 调用生成器函数并不会执行代码!

小白最容易踩坑的点:

python 复制代码
gen = simple_generator()
print(gen)
# 输出:

你会发现:一句print都没执行!

原因:调用生成器函数,只返回生成器对象,不执行函数体

函数真正执行,是在第一次调用next()时。

3.3 一步步执行next()

python 复制代码
gen = simple_generator()

# 第一次next
res1 = next(gen)
print("返回值:", res1)
# 输出:
# 第一步:开始执行
# 返回值: 1

# 第二次next
res2 = next(gen)
print("返回值:", res2)
# 输出:
# 第二步:恢复执行
# 返回值: 2

# 第三次next
res3 = next(gen)
print("返回值:", res3)
# 输出:
# 第三步:最后执行
# 返回值: 3

# 第四次next
next(gen)
# 抛出 StopIteration 异常

执行流程总结:

  1. 第一次next():从头跑到第一个yield,暂停,返回1
  2. 第二次next():从第一个yield下一行跑到第二个yield,暂停,返回2
  3. 第三次next():从第二个yield下一行跑到第三个yield,暂停,返回3
  4. 第四次next():函数跑完,无yield可执行,抛出StopIteration,迭代结束

这就是yield的完整生命周期:运行-暂停-恢复-暂停-...-结束

四、生成器核心原理:底层到底发生了什么?

2026年很多面试都会问:生成器底层是怎么实现状态保存的?

不用背八股,用通俗逻辑就能理解。

4.1 生成器 = 函数 + 状态机

从底层看,生成器对象内部维护了三个关键东西:

  1. 指令指针(Instruction Pointer):记录上次停在哪一行
  2. 局部变量栈:保存所有变量值,不释放
  3. 运行状态:GEN_SUSPENDED(暂停)、GEN_RUNNING(运行)、GEN_CLOSED(关闭)

普通函数:调用->运行->结束->销毁栈

生成器函数:调用->创建对象->next->运行->暂停->保存栈->next->恢复栈->继续运行

4.2 为什么生成器极省内存?

普通列表:

python 复制代码
# 1亿个整数,大约占用400MB+内存(2026实测)
a = [i for i in range(100_000_000)]

生成器:

python 复制代码
# 永远只保存当前状态,内存占用几乎不变(KB级别)
g = (i for i in range(100_000_000))

因为生成器不存储全部结果,只存储计算规则和当前状态,每next一次,计算一次值,用完即丢(除非你手动存)。

在2026年大模型训练数据加载、流式日志处理中,这一点是决定性优势。

五、生成器的两种写法:函数式 & 表达式式

5.1 生成器函数(带yield的函数)

就是我们上面写的:

python 复制代码
def gen_func():
    yield 1
    yield 2

适用场景:复杂逻辑、循环嵌套、文件读取、数据处理流水线。

5.2 生成器表达式(2026最常用简写)

类似列表推导式,把[]换成()

python 复制代码
gen = (x * 2 for x in range(1000))

极简、优雅,适合简单逻辑。

注意区分:

  • []:列表推导式,立即创建所有元素
  • ():生成器表达式,惰性生成

六、实战:生成器最常用的4大场景(2026最新实战)

6.1 超大文件读取(必掌握)

处理10GB、100GB日志文件,不能一次性读进内存:

python 复制代码
def read_large_file(file_path):
    with open(file_path, 'r', encoding='utf-8') as f:
        for line in f:
            yield line.strip()

# 逐行读取,内存永远只存一行
for line in read_large_file("big_log.log"):
    process(line)

这是2026年后端、数据开发必会写法

6.2 无限序列生成(不爆内存)

python 复制代码
def infinite_counter():
    num = 0
    while True:
        yield num
        num += 1

# 想取多少取多少,不会死循环爆内存
gen = infinite_counter()
print(next(gen)) # 0
print(next(gen)) # 1
print(next(gen)) # 2

用于ID生成、数据流、AI样本生成等场景。

6.3 数据流水线/管道(Pythonic核心)

多个生成器串联,形成数据流:

python 复制代码
def num_gen():
    for i in range(10):
        yield i

def square_gen(nums):
    for num in nums:
        yield num ** 2

def even_gen(nums):
    for num in nums:
        if num % 2 == 0:
            yield num

# 流水线:原始数 -> 平方 -> 过滤偶数
pipeline = even_gen(square_gen(num_gen()))
for res in pipeline:
    print(res)

无中间列表,全程流式处理,内存极低。

6.4 协程基础(asyncio核心前身)

2026年异步编程遍地都是,而async/await底层就是基于生成器原理

yield可以实现任务切换,是协程的基石。

简单演示:

python 复制代码
def task1():
    yield "任务1暂停"
    yield "任务1恢复"

def task2():
    yield "任务2暂停"
    yield "任务2恢复"

g1 = task1()
g2 = task2()

next(g1) # 切换任务1
next(g2) # 切换任务2
next(g1) # 切回任务1

这就是协程"微线程"切换的核心思想。

七、生成器高级特性:send、close、throw(2026面试高频)

7.1 send():向生成器传值

yield不仅能返回值,还能接收外部传入的值

python 复制代码
def generator_with_send():
    val = yield "开始"
    print("接收外部值:", val)
    yield "结束"

gen = generator_with_send()
print(next(gen))       # 输出:开始
print(gen.send("666")) # 传入666,输出:结束

执行逻辑:

  • send(value)会恢复生成器,并把value赋给yield表达式
  • 第一次必须用next(),不能直接send

7.2 close():手动关闭生成器

关闭后,生成器直接进入GEN_CLOSED状态:

python 复制代码
gen = (i for i in range(10))
gen.close()
next(gen) # StopIteration

用于资源释放、中断数据流。

7.3 throw():向生成器抛异常

python 复制代码
def gen():
    try:
        yield 1
    except ValueError:
        print("捕获到异常")

g = gen()
next(g)
g.throw(ValueError)

用于错误控制、数据流中断。

八、yield from:2026必备简化语法

yield from是Python 3.3+引入,2026年已是标准写法,用于委托生成器

8.1 不用yield from的嵌套

python 复制代码
def nested_gen():
    for i in [1,2,3]:
        yield i

def main_gen():
    for i in nested_gen():
        yield i

8.2 用yield from极简写法

python 复制代码
def main_gen():
    yield from [1,2,3]

yield from可以:

  • 直接迭代子生成器
  • 自动处理StopIteration
  • 支持双向传值(send穿透)

在多层生成器嵌套、异步生成器中必不可少。

九、常见误区与避坑指南(2026实测)

9.1 生成器只能迭代一次!

python 复制代码
gen = (i for i in range(3))
print(list(gen)) # [0,1,2]
print(list(gen)) # [] 空了!

生成器是一次性迭代器,跑完就废,想复用必须重新创建。

9.2 不要在生成器里做耗时阻塞操作

虽然省内存,但如果yield内部有阻塞IO,依然会拖慢整个流程,2026年推荐搭配异步生成器async def + async for

9.3 生成器不是线程安全

多线程同时操作同一个生成器会导致状态混乱,必须加锁。

十、总结:yield 核心原理一句话吃透

最后用最精炼的话总结yield与生成器:

  1. yield = 函数暂停 + 状态保存 + 返回值
  2. 生成器 = 惰性迭代器 + 状态机 + 内存优化
  3. 执行流程:创建→next运行→yield暂停→next恢复→循环直至结束
  4. 核心价值:处理海量数据、流式IO、协程基石、Pythonic编程

2026年的今天,yield早已不是高级技巧,而是Python开发者的基本功。无论是AI开发、后端高并发、数据处理,学会yield,你的代码会更高效、更优雅、更符合现代Python工程规范。

P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看,传送门https://blog.csdn.net/HHX_01

相关推荐
太子釢1 分钟前
手写一个 RAG:从零搭建可溯源的检索增强问答系统
人工智能
不吃辣4908 分钟前
vibe coding | 如何做一个 AI 音乐生成工具?
java·人工智能·后端·ai·ai编程
文人sec11 分钟前
从接口压测到全链路质量保障:AI智能客服系统的软件测试实践
人工智能
声讯电子11 分钟前
实测A-59F音频模组:降噪稳、不啸叫、通话清晰
人工智能·语音识别·ai降噪·usb接口·回音消除
神奇霸王龙16 分钟前
2026旗舰六阶段MCP流水线实战指南
人工智能·ai·ai作画·prompt·aigc·mcp
山河不见老19 分钟前
【Cursor 、Qoder安装问题】Cursor 、Qoder安装卡在“正在准备安装”问题排查及解决
人工智能·windows·编辑器
新知图书19 分钟前
2.3 开发工作流
人工智能·agent·ai agent·智能体
tuanxiang21 分钟前
用免费 AI 改写工具处理批量文案的踩坑记录,附完整降噪脚本
人工智能
小邓的技术笔记22 分钟前
DeepSeek 大模型落地应用与场景实战指南
大数据·人工智能
石榴28 分钟前
从 Codex + Obsidian 到本地 RAG:我的私人知识库实践
人工智能