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

相关推荐
AI2512242 小时前
AI文生视频技术解析:主流工具的模型架构与能力对比
人工智能·架构·音视频
pen-ai2 小时前
IRLS(迭代加权最小二乘)详解:基于 Huber Loss 的鲁棒回归
人工智能·数据挖掘·回归
阿杰学AI2 小时前
AI核心知识122—大语言模型之 直接偏好优化(简洁且通俗易懂版)
人工智能·算法·机器学习·ai·强化学习·dpo·直接优化偏好
克里斯蒂亚诺·罗纳尔达2 小时前
智能体学习22——智能体间通信(A2A)
人工智能·学习·ai
算力百科小星2 小时前
Web3.0节点部署专用:双卡GPU算力租用,延迟≤4ms
人工智能·图像渲染·智星云
东离与糖宝2 小时前
计算机网络五层模型:基础架构一次讲清
人工智能
LJ97951112 小时前
从“人找渠道”到“渠道找人”:2026年媒介宣发的AI解法
人工智能
新加坡内哥谈技术2 小时前
GPU计算的起源
人工智能