概要

python中的生成器是一种特殊的迭代器,如果按照c语言的说法,就是一种特殊的指针,但是python语言的一个语言特性是兼容了函数化编程,类似lambda匿名函数机制。

本文重点介绍生成器表达式的使用,是一种很快捷,节约内存的写法。

生成器(Generator)是一种特殊的迭代器,它能让你用一种非常高效的方式遍历序列。它的核心思想是:按需生成数据,而不是一次性创建所有数据。

想象一下你有一百万个数字要处理。如果你把它们全部加载到内存中,可能会导致程序变慢甚至崩溃。生成器就像一个“懒惰”的工厂,它只在你需要下一个数字时,才生产并提供给你,用完就丢弃,因此它能大大节省内存。

生成器和普通函数的区别

生成器看起来像一个普通的函数,但它最大的不同是使用 yield 关键字而不是 return

  • return:当你调用一个普通函数时,它会执行到 return 语句,然后返回一个值,并彻底结束。下次再调用这个函数时,它会从头开始执行。

  • yield:当你调用一个生成器函数时,它会执行到 yield 语句,然后返回一个值并暂停。它的状态(包括所有局部变量和执行位置)会被保存下来。下次你再次要求它提供值时,它会从上次暂停的地方继续执行,直到遇到下一个 yield

怎么创建生成器?

有两种主要方式创建生成器:

1. 生成器函数

这是最常见的方式,和定义普通函数一样,只是将 return 换成 yield

def simple_generator():yield 1yield 2yield 3# 调用生成器函数,会返回一个生成器对象
gen = simple_generator()# 每次调用 next(),它都会继续执行到下一个 yield
print(next(gen))  # 输出: 1
print(next(gen))  # 输出: 2
print(next(gen))  # 输出: 3# 当没有更多的 yield 语句时,会引发 StopIteration 异常
# print(next(gen))  # 这行会报错

通常,我们会用 for 循环来遍历生成器,因为 for 循环会自动处理 StopIteration 异常。

for item in simple_generator():print(item)
# 输出:
# 1
# 2
# 3
2. 生成器表达式

伪代码演示:

(你想生成什么 for 你要迭代什么 in 哪个序列 if 你的条件)

这是一种更简洁的写法,类似于列表推导式,但用圆括号 () 而不是方括号 []

  • 列表推导式(List Comprehension):一次性生成所有数据,并存入列表。

squares_list = [x*x for x in range(10)]
print(squares_list) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  • 生成器表达式(Generator Expression):按需生成数据,返回一个生成器对象。

squares_gen = (x*x for x in range(10))
print(squares_gen) # <generator object <genexpr> at ...># 只有当你遍历它时,数据才会被生成
for item in squares_gen:print(item)

生成器与列表的区别

从整体来看,区别最大的就是生成器的内存占用是很小的,下面看一个例子:

列表 (List) 的内存消耗

当你使用列表推导式或手动构建一个列表时,Python 会立即分配足够的内存来存储所有的元素。

例如:

all_squares = [x*x for x in range(1, 1000001)]

要执行这行代码,Python 会一次性计算 100 万个数字的平方,并将它们全部存储在一个列表中。如果每个整数占用 4 字节,那么这个列表至少需要 1,000,000 * 4 = 4 MB 的内存,再加上列表本身的一些开销。

这个过程是立即的、一次性的。这很方便,但如果数据量非常大,它可能会耗尽你的系统内存,导致程序崩溃或运行缓慢。

生成器 (Generator) 的内存消耗

与列表不同,生成器是惰性求值的。它不会一次性计算并存储所有元素。它只在需要时才计算下一个值。

例如:

all_squares_gen = (x*x for x in range(1, 1000001))

当你执行这行代码时,Python 并没有做任何计算。它只是创建了一个生成器对象。这个对象只存储了如何计算下一个值的指令(即 x*x)以及当前的状态(即 x 的值)。

当你开始迭代这个生成器时,比如在一个 for 循环中,它会一个接一个地生成值,并且只在内存中保留当前正在使用的那个值

类型工作原理内存使用
列表一次性创建并存储所有元素。消耗大量内存,与元素数量成正比。
生成器逐个按需生成元素。消耗极少内存,与元素数量无关。

生成器有这样的优点,归功于python这样高级语言的自动垃圾回收机制

生成器:即时分配,即时销毁

当生成器在 for 循环中被调用时,它会:

  1. 计算下一个值。

  2. 返回这个值。

  3. 立即释放与这个值相关的内存。

上面的例子里,生成器每计算一次,就会把上一次的计算好的数据删除回收,节约了空间。

生成器具体应用例子

下面是两端程序,实现的内容是一样的,但是第一个使用一般的函数定义写的,第二个是用匿名函数lambda和生成器写的,比较两者的区别

def count_fives(n):"""Return the number of values i from 1 to n (including n)where sum_digits(n * i) is 5.>>> count_fives(10)  # Among 10, 20, 30, ..., 100, only 50 (10 * 5) has digit sum 51>>> count_fives(50)  # 50 (50 * 1), 500 (50 * 10), 1400 (50 * 28), 2300 (50 * 46)4"""i = 1count = 0while i <= n:if sum_digits(n * i) == 5:count += 1i += 1return countdef count_primes(n):"""Return the number of prime numbers up to and including n.>>> count_primes(6)   # 2, 3, 53>>> count_primes(13)  # 2, 3, 5, 7, 11, 136"""i = 1count = 0while i <= n:if is_prime(i):count += 1i += 1return count

第二段

def sum_digits(y):"""Return the sum of the digits of non-negative integer y."""total = 0while y > 0:total, y = total + y % 10, y // 10return totaldef is_prime(n):"""Return whether positive integer n is prime."""if n == 1:return Falsek = 2while k < n:if n % k == 0:return Falsek += 1return Truedef count_cond(condition):"""Returns a function with one parameter N that counts all the numbers from1 to N that satisfy the two-argument predicate function Condition, wherethe first argument for Condition is N and the second argument is thenumber from 1 to N.>>> count_fives = count_cond(lambda n, i: sum_digits(n * i) == 5)>>> count_fives(10)   # 50 (10 * 5)1>>> count_fives(50)   # 50 (50 * 1), 500 (50 * 10), 1400 (50 * 28), 2300 (50 * 46)4>>> is_i_prime = lambda n, i: is_prime(i) # need to pass 2-argument function into count_cond>>> count_primes = count_cond(is_i_prime)>>> count_primes(2)    # 21>>> count_primes(3)    # 2, 32>>> count_primes(4)    # 2, 32>>> count_primes(5)    # 2, 3, 53>>> count_primes(20)   # 2, 3, 5, 7, 11, 13, 17, 198""""*** YOUR CODE HERE ***"return lambda n: sum(1 for i in range(1,n+1) if condition(n,i))

套用生成器表达式:

(你想生成什么 for 你要迭代什么 in 哪个序列 if 你的条件)

这个代码意味着遍历1到n的序列,如果条件满足condition,则生成1,而外部的sum()函数就会把1加起来,实现计数。

一行就解决了这个问题,函数式编程的泛用性可见一斑

为什么使用生成器?

  1. 节省内存:这是最大的优势。它不会一次性把所有数据都存到内存里,特别适合处理大数据集。

  2. 延迟计算:数据只在需要时才被生成,这对于某些计算密集型任务非常有用。

  3. 可读性高:生成器函数比编写一个自定义迭代器类要简单得多。

总结

  • 生成器是按需生成数据的迭代器。

  • yield 关键字创建生成器函数

  • 用圆括号 () 创建生成器表达式

  • 它们的主要优点是内存高效延迟计算

如果你需要处理大量数据或者进行无限序列的操作,生成器是 Python 中一个非常有用的工具。

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

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

相关文章

【Coze】Windows 环境下使用 Docker 部署 Coze Studio 的详细指南

一、前言&#xff1a; Coze Studio 是一站式 AI Agent 开发工具。提供各类最新大模型和工具、多种开发模式和框架&#xff0c;从开发到部署&#xff0c;为你提供最便捷的 AI Agent 开发环境。 提供 AI Agent 开发所需的全部核心技术&#xff1a;Prompt、RAG、Plugin、Workflo…

票务系统小程序源码

1. 系统概述 github地址 本系统是一个历经多年迭代和市场检验的综合性智慧票务解决方案。它以小程序和后台管理系统为核心&#xff0c;深度整合了线上OTA渠道、线下多种支付方式以及各类智能硬件&#xff0c;为旅游景区、展馆、活动中心等场景提供稳定、高效、功能完备的一体化…

Python 文件操作与异常处理全解析

目录 一、文件的基本概念 1. 什么是文件 2. 文件操作的核心内容 3. 文件操作的作用 二、文件的基本操作 1. 文件操作三步走 2. 打开文件&#xff1a;open () 函数 2.1 文件路径 2.2 常用 mode 模式 3. 写入文件&#xff1a;write () 函数 4. 关闭文件&#xff1a;cl…

领码方案:通用物联网数据采集低代码集成平台——万物智联时代的黄金钥匙

摘要&#xff1a; 领码方案通过“协议抽象层低代码引擎AI智能中枢”架构&#xff0c;实现物联网设备数据采集、存储、分析的零代码配置化集成。支持200工业协议即插即用&#xff0c;10分钟完成设备上云&#xff0c;数据流转效率提升70%&#xff0c;AI模型调用耗时降低90%。该方…

后台管理系统-10-vue3之用户管理组件配置子路由和静态页面

文章目录 1 配置子路由 1.1 router/index.js(添加路由) 1.2 views/User.vue(用户管理) 1.3 验证路由是否生效 2 User.vue(静态页面) 2.1 搜索框和表格的静态搭建 2.2 用户表格的数据获取渲染 2.2.1 user.js(准备数据) 2.2.2 mock.js(拦截请求的URL) 2.2.3 api.js(axios请求的UR…

AMPAK正基科技系列产品有哪些广泛应用于IOT物联网

關於正基AMPAK 智慧物聯網 無線射頻模組專家 專業品牌 正基科技是一家擁有超過 20 年無線模組研發、設計、生產、行銷與產品技術整合服務經驗的公司。 有專業的高頻模組硬體設計及軟體整合工程師團隊&#xff0c;具備豐富的客戶應用經驗&#xff0c;能因應客戶與市場導向的產品…

【PyTorch】环境配置

文章目录1. 配置cuda环境2. 配置conda环境3. 配置pytorch gpu环境1. 配置cuda环境 在命令行输入以下命令可以查看当前显卡驱动版本和最高支持的cuda版本 nvidia-smi根据cuda版本去官网下载并安装cuda 下载链接&#xff1a;https://developer.nvidia.com/cuda-toolkit-archive…

vue3实现实现手机/PC端录音:recorder-core

通过 recorder-core 这个插件实现录音recorder-core插件使用下方的js文件是安装后封装的一个js文件&#xff0c;在需要使用的地方直接引入这个文件&#xff1a;import record from “./recorderCore.js”;// 文件名称&#xff1a;recorderCore.js// recorder-core插件使用方式…

deepseek 本地部署,如何支持工具调用

这里需要考虑显卡是否和模型匹配&#xff0c;支不支持推理 先把模版拉取到本地&#xff1a;git clone https://github.com/sgl-project/sglang.git 我的位置是 /data/home/sglang 注意模版位于sglang下的examples/chat_template中 根据对应的模版部署模型&#xff0c;比如 …

Excel中运行VB的函数

“插入” -》 “模块”Function FormatCodeFlex(inputStr As String, Optional defaultVal As String "0") As StringOn Error GoTo ErrorHandlerDim parts() As StringDim i As Integer 使用 "-" 分割字符串parts Split(inputStr, "-") 确保至…

《零基础入门AI:深度学习之NLP基础学习》

一、自然语言处理&#xff08;NLP&#xff09;概述 1. 基本概念 ​ 自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;是人工智能与计算语言学交叉的核心领域&#xff0c;致力于实现计算机对人类自然语言的自动理解、分析、生成与交互。其研究目标在于构…

保姆级Debezium抽取SQL Server同步kafka

前言&#xff1a; Debezium SQL Server连接器捕获SQL Server数据库模式中发生的行级更改。 官方2.0文档&#xff1a; Debezium connector for SQL Server :: Debezium Documentation 有关与此连接器兼容的SQL Server版本的信息&#xff0c;请参阅 SQL Server Database: 201…

鸿蒙安卓前端中加载丢帧:ArkWeb分析

序章&#xff1a;卡顿的数字世界 在每秒60帧的视觉交响乐中&#xff0c;每一帧都是精心编排的节拍。当这些节拍开始丢失——就像交响乐中突然静音的提琴部——我们便遭遇了加载丢帧的数字噩梦。这不是简单的性能下降&#xff0c;而是一场渲染管线的全面崩溃&#xff0c;是数字…

Spring Cloud Netflix学习笔记06-Zuul

文章目录概述什么是Zuul?Zuul 能干嘛&#xff1f;Zuul入门案例pom依赖application.yml启动类隐藏真实路径概述 什么是Zuul? Zuul包含了对请求的路由(用来跳转的)和过滤两个最主要功能&#xff1a; 其中路由功能负责将外部请求转发到具体的微服务实例上&#xff0c;是实现外…

c# 和 c++ 怎样结合

c# 和 c 怎样结合在软件开发中&#xff0c;C# 和 C 通常用于不同的场景和目的&#xff0c;但有时需要将它们结合使用以充分利用两种语言的优点。以下是几种常见的方法来实现 C# 和 C 的结合&#xff1a;1. P/Invoke&#xff08;Platform Invocation Services&#xff09;P/Invo…

开源分布式数据库(Dgraph)

Dgraph 是一款专为处理复杂关系数据设计的开源分布式图数据库&#xff0c;核心目标是提供高性能、高可扩展性的图数据存储与查询能力。其设计融合了原生图模型与分布式架构&#xff0c;支持 GraphQL 查询语言&#xff0c;适用于社交网络、知识图谱、推荐系统等场景。 一、技术架…

Apache ShenYu和Nacos之间的通信原理

这是一个非常经典的服务注册发现和动态配置管理的案例。ShenYu 作为网关,需要实时感知后端微服务的上线、下线以及其元数据信息(如 API 接口列表)的变化,同时它自身的配置也可能需要动态调整。Nacos 则作为注册中心和配置中心,扮演了“服务电话簿”和“动态配置仓库”的角…

强制重启导致Ubuntu24.04LTS amd的WIFI无法使用的解决方案

强制重启导致Ubuntu24.04LTS amd的WIFI无法使用的解决方案 前言 ‍ 我按下了<ctrl><alt><prtsc>组合键&#xff0c;然后按住<ctrl><alt>不放&#xff0c;让我的死机的图形化的Ubuntu强制重启&#xff0c;然后再次打开发现&#xff0c;我的ubu…

Java基础面试题02

引用&#xff1a;&#xff08;代码随想录的八股转免费了&#xff09;以下为网址 卡码笔记 本文为学习以上文章的笔记&#xff0c;如果有时间推荐直接去原网址 Java中的数据类型有哪些&#xff1f;分为哪两大类&#xff1f; (考点&#xff1a;Java数据类型及其分类) 【简单】 基…

RabbitMQ:SpringAMQP Fanout Exchange(扇型交换机)

目录一、案例需求二、基础配置三、代码实现扇形交换机也叫做广播交换机&#xff0c;通过交换机将消息发送给所有的队列。 生产者源码 消费者源码 一、案例需求 在RabbitMQ控制台中&#xff0c;声明队列fanout.queue1和fanout.queue2。在RabbitMQ控制台中&#xff0c;声明交换…