python 函数—生成器

Python 生成器(Generator)

目录

  1. 什么是生成器
  2. 生成器语法
    • 生成器函数
    • 生成器表达式
  3. 生成器的工作原理
  4. 使用方法
    • 通过next()函数
    • 通过for循环
    • 其他方法
  5. 应用场景
  6. 生成器表达式与列表推导式的区别
  7. 常见问题与陷阱

什么是生成器

生成器(Generator)是Python中的一种特殊类型的迭代器(Iterator),它能够按需生成值,而不是一次性生成所有值。与列表、元组等容器类型的可迭代对象不同,生成器不会将所有数据存储在内存中,而是在每次请求时"即时"生成数据。

生成器的关键特点:

  • 是特殊的迭代器,遵循迭代器协议
  • 使用yield语句生成值并暂停执行
  • 函数状态会被保存,下次调用时从暂停处继续
  • 每次调用只提供一个数据
  • 不能"回头"访问已生成的值
  • 支持next()函数调用
  • 不支持下标索引访问
  • 惰性计算,按需生成数据

生成器语法

Python中创建生成器有两种方式:通过生成器函数或生成器表达式。

生成器函数

生成器函数是包含yield关键字的常规函数。当调用生成器函数时,它返回一个生成器对象,而不执行函数体。

def simple_generator():"""一个简单的生成器函数"""print("开始执行")yield 1print("第一次yield之后")yield 2print("第二次yield之后")yield 3print("结束")# 创建生成器对象
gen = simple_generator()
# 此时函数体尚未执行

生成器表达式

生成器表达式是创建生成器的简洁语法,类似于列表推导式,但使用圆括号而不是方括号。

# 生成器表达式
gen_expr = (x ** 2 for x in range(5))

生成器的工作原理

生成器的核心机制是函数执行的暂停与恢复:

  1. 当调用生成器函数时,返回一个生成器对象,但函数体不执行
  2. 当第一次调用next()方法时,函数开始执行,直到遇到yield语句
  3. yield语句返回一个值,并且函数执行暂停,保存所有当前的状态(局部变量等)
  4. 下一次调用next()方法时,函数从上次暂停的地方继续执行
  5. 当函数执行完毕时,生成器抛出StopIteration异常

这种机制使得生成器能够"记住"它的状态,并在每次需要时生成下一个值。

使用方法

通过next()函数

可以使用内置的next()函数来获取生成器的下一个值:

def count_up_to(max):count = 1while count <= max:yield countcount += 1counter = count_up_to(3)
print(next(counter))  # 输出: 1
print(next(counter))  # 输出: 2
print(next(counter))  # 输出: 3try:print(next(counter))  # 抛出StopIteration异常
except StopIteration:print("生成器已耗尽")

通过for循环

更常见的是使用for循环遍历生成器的值:

# 使用for循环遍历生成器
for num in count_up_to(5):print(num)
# 输出: 1 2 3 4 5

其他方法

生成器对象还有其他高级方法:

  1. send() - 向生成器内部发送值
def echo_generator():value = yield "准备接收"print(f"收到: {value}")while True:value = yield f"你发送了: {value}"print(f"收到: {value}")gen = echo_generator()
print(next(gen))      # 初始化生成器,输出: 准备接收
print(gen.send("你好"))  # 发送值并获取下一个值,输出: 你发送了: 你好
  1. throw() - 向生成器内部抛出异常
def generator_with_exception():try:yield 1yield 2except ValueError:yield 'Got ValueError!'g = generator_with_exception()
print(next(g))        # 输出: 1
print(g.throw(ValueError))  # 输出: Got ValueError!
  1. close() - 关闭生成器
def closable_generator():try:yield 1yield 2yield 3finally:print("生成器被关闭")g = closable_generator()
print(next(g))  # 输出: 1
g.close()       # 关闭生成器,输出: 生成器被关闭

应用场景

1. 处理大文件

生成器特别适合处理大文件,因为它们不需要一次性将整个文件加载到内存中:

def read_large_file(file_path):with open(file_path, 'r') as file:for line in file:yield line.strip()# 逐行处理大文件
for line in read_large_file('huge_file.txt'):# 处理每一行...pass

2. 生成无限序列

生成器可以轻松创建无限序列,只在需要时计算值:

def fibonacci():a, b = 0, 1while True:yield aa, b = b, a + b# 获取斐波那契数列的前10个数
fib_gen = fibonacci()
fibs = [next(fib_gen) for _ in range(10)]
print(fibs)  # 输出: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

3. 数据流处理和管道

生成器可用于创建数据处理管道,每个生成器负责一个处理步骤:

def read_data(file_path):with open(file_path, 'r') as file:for line in file:yield line.strip()def parse_data(lines):for line in lines:# 解析每行数据yield line.split(',')def filter_data(parsed_lines):for items in parsed_lines:if len(items) >= 3 and items[2].isdigit():yield items# 构建数据处理管道
lines = read_data('data.csv')
parsed = parse_data(lines)
filtered = filter_data(parsed)for item in filtered:print(item)

4. 提高内存效率

对比处理100万个数的平方的两种方式:

# 使用列表 - 占用大量内存
squares_list = [i ** 2 for i in range(1000000)]
sum_squares = sum(squares_list)# 使用生成器 - 内存高效
sum_squares = sum(i ** 2 for i in range(1000000))

生成器表达式与列表推导式的区别

特性生成器表达式列表推导式
语法使用圆括号 (x for x in range(10))使用方括号 [x for x in range(10)]
内存使用惰性计算,内存高效一次性创建所有元素,占用更多内存
计算时机按需计算立即计算所有值
访问方式只能顺序访问,不能索引可以通过索引随机访问
重复使用只能遍历一次可以多次遍历
速度生成值时可能稍慢,但初始化快初始化慢,但访问值更快

示例:

# 列表推导式
list_comp = [x ** 2 for x in range(5)]
print(list_comp)        # 输出: [0, 1, 4, 9, 16]
print(list_comp[2])     # 输出: 4
print(sum(list_comp))   # 输出: 30
print(sum(list_comp))   # 还可以再次使用,输出: 30# 生成器表达式
gen_expr = (x ** 2 for x in range(5))
# print(gen_expr[2])    # 错误:生成器不支持索引访问
print(sum(gen_expr))    # 输出: 30
print(sum(gen_expr))    # 输出: 0 (生成器已耗尽,不能重用)

常见问题与陷阱

1. 生成器耗尽后不能重新使用

一旦生成器被完全迭代,它就不能被重置或重新使用:

def count_to_three():yield 1yield 2yield 3gen = count_to_three()
print(list(gen))  # 输出: [1, 2, 3]
print(list(gen))  # 输出: [] (生成器已耗尽)

2. 在生成器上使用列表函数会消耗生成器

将生成器转换为列表会消耗生成器:

gen = (x for x in range(5))
data = list(gen)  # 将生成器转换为列表
print(data)       # 输出: [0, 1, 2, 3, 4]
print(list(gen))  # 输出: [] (生成器已被消耗)

3. 生成器的延迟绑定

在生成器中使用循环变量时要小心延迟绑定:

# 错误的做法
funcs = [lambda: i for i in range(5)]
results = [f() for f in funcs]
print(results)  # 输出: [4, 4, 4, 4, 4]# 正确的做法
funcs = [(lambda j=i: j) for i in range(5)]
results = [f() for f in funcs]
print(results)  # 输出: [0, 1, 2, 3, 4]

总结

  • 生成器是一种特殊的迭代器,能够按需生成值,节省内存
  • 使用yield关键字创建生成器函数,或使用生成器表达式
  • 生成器在每次调用时暂停执行并保存状态
  • 生成器特别适合处理大型数据集、无限序列和数据流
  • 与列表不同,生成器只能前进不能后退,且不支持索引访问
  • 生成器表达式比列表推导式更节省内存,但只能遍历一次
  • 使用生成器能显著提高程序的内存效率和可扩展性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/38528.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv11 目标检测

本文章不再赘述anaconda的下载以及虚拟环境的配置&#xff0c;博主使用的python版本为3.8 1.获取YOLOv11的源工程文件 链接&#xff1a;GitHub - ultralytics/ultralytics: Ultralytics YOLO11 &#x1f680; 直接下载解压 2.需要自己准备的文件 文件结构如下&#xff1a;红…

【Linux】——环境变量与进程地址空间

文章目录 环境变量环境变量的概念常见的环境变量PATH相关指令 main的三个参数前两个参数第三个参数 程序地址空间进程地址空间 环境变量 环境变量的概念 环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数&#xff0c;将来会以shell的形式传递给所有进程&…

Kafka--常见问题

1.为什么要使用 Kafka&#xff0c;起到什么作用 Kafka是一个高吞吐量、分布式、基于发布订阅的消息系统&#xff0c;它主要用于处理实时数据流 Kafka 设计上支持高吞吐量的消息传输&#xff0c;每秒可以处理数百万条消息。它能够在处理大量并发请求时&#xff0c;保持低延迟和…

Flutter:页面滚动,导航栏背景颜色过渡动画

记录&#xff1a;导航默认透明&#xff0c;页面发生滚动后&#xff0c;导航背景色由0-1&#xff0c;过渡到白色背景。 view import package:ducafe_ui_core/ducafe_ui_core.dart; import package:flutter/material.dart; import package:get/get.dart; import package:redo…

探秘格式化:数据危机与恢复之道

引言 在数字化飞速发展的当下&#xff0c;数据已然成为我们生活中不可或缺的一部分。无论是珍贵的家庭照片、重要的工作文档&#xff0c;还是企业关键的业务数据&#xff0c;都承载着我们的回忆、努力和希望。然而&#xff0c;格式化这一操作却如同隐藏在数字世界中的“幽灵”…

人工智能 - 通用 AI Agent 之 LangManus、Manus、OpenManus 和 OWL 技术选型

一、核心项目概览 1. Manus(闭源通用 AI Agent) 定位 :全球首个全流程自动化通用 AI Agent,GAIA 基准测试 SOTA 水平。核心能力 : 全流程自动化 :从任务规划(如撰写报告)到执行(代码生成、表格制作)的端到端处理。智能纠错机制 :基于沙箱环境的实时错误反思与调整…

封装一个分割线组件

最终样式 Vue2代码 <template><div class"sep-line"><div class"sep-label"><span class"sep-box-text"><slot>{{ title }}</slot> <!-- 默认插槽内容&#xff0c;如果没有传递内容则使用title -->&…

走进Java:String字符串的基本使用

❀❀❀ 大佬求个关注吧~祝您开心每一天 ❀❀❀ 目录 一、什么是String 二、如何定义一个String 1. 用双引号定义 2. 通过构造函数定义 三、String中的一些常用方法 1 字符串比较 1.1 字符串使用 1.2 字符串使用equals() 1.3 使用 equalsIgnoreCase() 1.4 cpmpareTo…

第2.2节 Android Jacoco插件覆盖率采集

JaCoCo&#xff08;Java Code Coverage&#xff09;是一款开源的代码覆盖率分析工具&#xff0c;适用于Java和Android项目。它通过插桩技术统计测试过程中代码的执行情况&#xff0c;生成可视化报告&#xff0c;帮助开发者评估测试用例的有效性。在github上开源的项目&#xff…

OpenGL ES ->乒乓缓冲,计算只用两个帧缓冲对象(Frame Buffer Object)+叠加多个滤镜作用后的Bitmap

乒乓缓冲核心思想 不使用乒乓缓冲&#xff0c;如果要每个滤镜作用下的绘制内容&#xff0c;也就是这个滤镜作用下的帧缓冲&#xff0c;需要创建一个Frame Buffer Object加上对应的Frame Buffer Object Texture使用乒乓缓冲&#xff0c;只用两个Frame Buffer Object加上对应的F…

Unity导出WebGL,无法加载,data文件无法找到 404(NotFound)

问题&#xff1a;data文件无法找到404Not found 示例是使用IIS托管启动 F12可以看到not found 的报错 解决办法&#xff1a; iis无法识别data文件&#xff0c;在MIME类型中增加data 类型&#xff1a;application/octet-stream 添加之后&#xff0c;会在根目录下生产一个…

C++与OO思想的联系

一、C与OO思想的联系 C&#xff1a;OO思想&#xff08;面向对象--属性和行为&#xff09; 任何事务都可以被看做一个个对象&#xff0c;一个再复杂的模型结构都是由千千万万个对象组成。 OO思想两个要素&#xff1a;属性和行为(方法)。 OO思想的特点&#xff1a; 封装&#x…

单表达式倒计时工具:datetime的极度优雅(DeepSeek)

一个简单表达式&#xff0c;也可以优雅自成工具。 笔记模板由python脚本于2025-03-22 20:25:49创建&#xff0c;本篇笔记适合任意喜欢学习的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思考与经验&#xff0c;而不仅仅是知识的简单复述。 Pyth…

Kubernetes的Replica Set和ReplicaController有什么区别

ReplicaSet 和 ReplicationController 是 Kubernetes 中用于管理应用程序副本的两种资源&#xff0c;它们有类似的功能&#xff0c;但 ReplicaSet 是 ReplicationController 的增强版本。 以下是它们的主要区别&#xff1a; 1. 功能的演进 ReplicationController 是 Kubernete…

CSS基础知识一览

持续维护 选择器 display 常用属性 浮动 弹性布局

IS-IS原理与配置

一、IS-IS概述 IS-IS&#xff08;Intermediate System to Intermediate System&#xff0c;中间系统到中间系统&#xff09;是ISO&#xff08;International Organization for Standardization&#xff0c;国际标准化组织&#xff09;为它的CLNP&#xff08;ConnectionLessNet…

【前端】Visual Studio Code安装配置教程:下载、汉化、常用组件、基本操作

文章目录 一、Visual Studio Code下载二、汉化三、常用组件1、Auto Rename Tag2、view-in-browser3、Live Server 四、基本操作五、感谢观看&#xff01; 一、Visual Studio Code下载 下载官网&#xff1a;https://code.visualstudio.com/ 进入官网后点击右上角的Download &…

git推送代码相关学习——(一)

推荐去阅读一下廖老师的git相关的教程https://liaoxuefeng.com/books/git/introduction/index.html 这个系列就来学习一下git操作。 第一步&#xff0c;新建项目 去github中新建一个项目&#xff0c;然后依据项目来进行本地的开发工作。 第二步&#xff0c;拉取项目 git c…

CMS网站模板设计与用户定制化实战评测

内容概要 在数字化转型背景下&#xff0c;CMS平台作为企业内容管理的核心载体&#xff0c;其模板架构的灵活性与用户定制能力直接影响运营效率。通过对WordPress、Baklib等主流系统的技术解构发现&#xff0c;模块化设计理念已成为行业基准——WordPress依托超过6万款主题库实…

Maya基本操作

基本操作 按住ALT键&#xff0c;左键旋转视角&#xff0c;中键平移视角&#xff0c;右键放大缩小视角。 按空格键切换4格视图。 导入FBX格式文件后&#xff0c;无贴图显示。 按6键开启。着色纹理显示 坐标轴相关 修改菜单-左键最上面的虚线。固定修改选项窗口。 选中物体…