Python中如何使用生成器?yield关键字详解

来源:站长源码作者:半夏头衔:草根站长
导读:本期聚焦于小伙伴创作的《Python中如何使用生成器?yield关键字详解》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Python中如何使用生成器?yield关键字详解》有用,将其分享出去将是对创作者最好的鼓励。

生成器是Python中一种特殊的迭代器,它不需要像列表那样提前把所有元素存储在内存中,而是在迭代过程中按需生成数据,非常适合处理大规模数据或者无限序列的场景。yield关键字是定义生成器的核心,理解它的工作机制就能轻松掌握生成器的使用方式。

Python中如何使用生成器?yield关键字详解

生成器的基本概念

生成器本质上是一种迭代器,它遵循迭代器协议,也就是实现了__iter____next__方法,但是不需要我们手动去实现这两个方法,Python解释器会自动处理。生成器的定义方式有两种,一种是通过生成器表达式,另一种是使用yield关键字定义生成器函数。

普通函数执行时会从第一行开始运行,直到遇到return语句或者函数结束才返回结果,然后函数的所有局部状态都会被销毁。而生成器函数在调用时不会立即执行函数体,而是返回一个生成器对象,只有当对这个对象调用next()方法或者进行迭代时,函数体才会开始执行。

yield关键字的工作原理

yield关键字的作用和return类似,都可以让函数返回结果,但是二者有本质区别:return会结束函数的执行,而yield只会暂停函数的执行,并且保存当前的局部状态,下次再调用next()时,会从yield暂停的位置继续执行。

我们可以通过一个简单的例子来理解这个过程:

def simple_generator():
    print("第一次执行,即将返回1")
    yield 1
    print("第二次执行,即将返回2")
    yield 2
    print("第三次执行,即将返回3")
    yield 3

# 创建生成器对象
gen = simple_generator()
# 第一次调用next,执行到第一个yield暂停
print(next(gen))  # 输出:第一次执行,即将返回1  换行后输出1
# 第二次调用next,从上次yield的位置继续执行
print(next(gen))  # 输出:第二次执行,即将返回2  换行后输出2
# 第三次调用next,从上次yield的位置继续执行
print(next(gen))  # 输出:第三次执行,即将返回3  换行后输出3
# 再次调用next,函数已经执行完毕,会抛出StopIteration异常
# next(gen)

从上面的例子可以看到,每次调用next(gen)时,生成器函数就会从上次暂停的位置继续执行,直到遇到下一个yield返回结果,再次暂停。当函数执行完所有代码没有遇到yield时,再调用next()就会抛出StopIteration异常,这也是迭代器结束的标志。

生成器的常见使用场景

1. 处理大规模数据

当我们需要处理一个非常大的数据集,比如读取一个几十GB的日志文件,如果一次性把文件内容全部读入内存,很容易导致内存溢出。这时候使用生成器逐行读取就可以避免这个问题:

def read_large_file(file_path):
    with open(file_path, 'r', encoding='utf-8') as f:
        # 逐行读取,每次只返回一行内容,不会占用大量内存
        for line in f:
            yield line.strip()

# 使用生成器读取文件
file_gen = read_large_file('large_log.txt')
# 迭代处理每一行,这里只打印前5行作为示例
count = 0
for line in file_gen:
    print(line)
    count += 1
    if count >= 5:
        break

2. 生成无限序列

生成器还可以用来生成无限序列,比如生成从0开始的自然数序列,普通列表是无法存储无限个元素的,但是生成器可以做到:

def natural_numbers():
    num = 0
    while True:
        yield num
        num += 1

# 创建自然数生成器
num_gen = natural_numbers()
# 获取前10个自然数
for i in range(10):
    print(next(num_gen))

3. 实现协程的基础

yield关键字还可以配合send()方法实现简单的协程,允许我们在生成器暂停的时候向生成器内部传递数据:

def coroutine_example():
    print("协程启动")
    while True:
        # 接收外部传递进来的值
        value = yield
        print(f"接收到的值:{value}")

# 创建协程对象
cor = coroutine_example()
# 启动协程,需要先调用next()或者send(None)
next(cor)
# 向协程内部传递数据
cor.send("第一个数据")
cor.send("第二个数据")
# 关闭协程
cor.close()

生成器和普通函数的区别

我们可以通过下面的表格清晰对比生成器函数和普通函数的差异:

对比项普通函数生成器函数
定义关键字无特殊关键字包含yield关键字
调用返回值返回具体的结果值返回生成器对象
执行逻辑执行到return结束,状态销毁执行到yield暂停,保存状态,下次继续
内存占用如果返回大列表会占用大量内存按需生成数据,内存占用极低
适用场景处理小规模数据,一次性返回结果处理大规模数据、无限序列、流式处理

生成器表达式的使用

除了使用yield定义生成器函数,Python还支持生成器表达式,语法和列表推导式类似,只是把方括号换成圆括号。生成器表达式会返回一个生成器对象,而不是一个列表:

# 列表推导式,会立即生成所有元素,占用内存
list_data = [x * 2 for x in range(10)]
print(type(list_data))  # 输出:<class 'list'>
print(list_data)  # 输出:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# 生成器表达式,返回生成器对象,按需生成元素
gen_data = (x * 2 for x in range(10))
print(type(gen_data))  # 输出:<class 'generator'>
# 迭代生成器获取数据
for num in gen_data:
    print(num)

生成器表达式适合简单的生成逻辑,如果生成逻辑比较复杂,还是建议使用生成器函数来定义,可读性会更好。

注意事项

  • 生成器对象只能迭代一次,迭代完之后就会耗尽,再次迭代不会返回任何数据,如果需要重复迭代,需要重新创建生成器对象。
  • 不要在生成器函数内部使用return返回具体的值,Python中生成器函数的return只能用来结束生成器,并且return返回的值会作为StopIteration异常的说明,不会被当作生成器的返回结果。
  • 使用send()方法向生成器传递数据时,第一次调用必须先调用next()或者send(None)来启动生成器,否则会抛出TypeError异常。

掌握生成器和yield关键字的使用,能够帮助我们写出更高效的Python代码,尤其是在处理大数据场景时,能大幅降低内存占用,提升程序的运行效率。

Python生成器yield关键字迭代器修改时间:2026-07-08 20:42:38

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。