当前位置: 首页 > news >正文

全网都在找的Python生成器竟然在这里!简单几步,让你的代码更简洁、更高效!

在这里插入图片描述

  • 博客主页:长风清留扬-CSDN博客
  • 系列专栏:Python基础专栏
  • 每天更新大数据相关方面的技术,分享自己的实战工作经验和学习总结,尽量帮助大家解决更多问题和学习更多新知识,欢迎评论区分享自己的看法
  • 感谢大家点赞👍收藏⭐评论

在这里插入图片描述

一、生成器的定义

生成器是一种特殊的迭代器,它允许你定义一个函数,该函数会按照你的要求生成一个序列的值,但一次只返回一个值,并且在内部维护着自己的状态,以便在需要时生成下一个值。生成器是通过使用yield关键字来实现的。
推荐阅读: 来看看Python迭代器能让你的代码提升100倍的密码

二、生成器的创建

生成器可以通过以下两种方式创建:

yield关键字

函数中包含yield关键字:当一个函数中包含至少一个yield语句时,该函数就不再是一个普通函数,而是一个生成器函数。调用该函数时,会返回一个生成器对象。
在Python中,yield关键字用于在函数中创建一个生成器。生成器是一种特殊的迭代器,它允许你逐个产生值,而不是一次性返回整个序列。使用yield关键字,你可以定义一个函数,该函数在每次调用时返回一个值,并保留其状态以供下次调用时继续执行。

语法

def generator_function_name(parameters):  """  这是一个生成器函数的定义。  :param parameters: 函数的参数,可以是任意数量和类型的参数。  :yield: 在函数体中,使用yield关键字来返回一个值,并暂停函数的执行。  每次迭代生成器时,函数会从上次yield的位置继续执行。  """  # 函数体:可以包含任意数量的语句和逻辑。  # 通常会有一个循环来逐个产生值。  for item in iterable:  # iterable是一个可迭代对象,比如列表、元组、集合或字符串等。  # 可以在这里进行任何需要的计算或处理。  yield value  # 使用yield返回一个值,并暂停函数的执行。  # 这里的代码(如果有的话)不会在每次迭代时都执行,  # 除非它位于另一个循环或条件语句中。  # 注意:生成器函数通常没有return语句(或者有一个不带值的return,表示迭代结束)。  # 如果有return语句并带有值,那么在迭代结束后尝试获取下一个值时,会引发StopIteration异常,  # 并且该值会被作为StopIteration异常的value属性返回(这是Python 3.3及以后版本的行为)。

示例1

def simple_generator():  """  一个简单的生成器函数,依次返回数字0到2。  """  yield 0  yield 1  yield 2  # 使用生成器函数  
gen = simple_generator()  # 创建一个生成器对象  # 迭代生成器对象  
for value in gen:  print(value)  # 输出:0, 1, 2

在上面的示例中,simple_generator是一个生成器函数,它使用yield关键字依次返回数字0、1和2。当我们调用这个函数时,它不会立即执行完并返回结果,而是返回一个生成器对象。然后,我们可以使用for循环或其他迭代方式来逐个获取生成器产生的值。

需要注意的是,生成器函数在每次迭代时都会从上次yield的位置继续执行,直到函数结束或再次遇到yield。这意味着你可以在生成器函数中保留状态(比如循环变量、内部变量等),并在下次迭代时继续使用它们。

示例2

def fibonacci(n):  """生成斐波那契数列的前n个数"""  a, b = 0, 1  for _ in range(n):  yield a  # 返回当前的斐波那契数  a, b = b, a + b  # 更新斐波那契数列的当前数和下一个数  # 使用生成器函数  
fib_gen = fibonacci(5)  # 创建一个生成器对象  
for num in fib_gen:  # 迭代生成器对象  print(num)  # 打印每个斐波那契数

运行结果:

0  
1  
1  
2  
3

生成器表达式

  • 生成器表达式:生成器表达式类似于列表推导式,但使用圆括号而不是方括号。它们提供了一种简洁的方法来创建生成器。
  • 生成器表达式是另一种创建生成器的方式,它提供了一种简洁的语法来生成序列的值。生成器表达式使用圆括号()而不是方括号[]来定义,并且它们也使用yield关键字(尽管在表达式中这种用法是隐式的)。

语法

generator_expression = (expression for item in iterable [if condition])
  • expression:要生成的值的表达式。
  • item:从可迭代对象iterable中取出的元素。
  • iterable:要遍历的可迭代对象。
  • if condition(可选):一个条件表达式,用于过滤要生成的元素。

示例

# 创建一个生成器表达式,生成从0到9的平方数  
squares = (x**2 for x in range(10))  # 使用for循环迭代生成器表达式  
for square in squares:  print(square)

运行结果:

0  
1  
4  
9  
16  
25  
36  
49  
64  
81

生成器表达式在语法上类似于列表推导式,但它们不会一次性生成整个列表,而是返回一个生成器对象,该对象在迭代时按需生成值。这使得生成器表达式在处理大数据集时更加高效,因为它们不会占用大量内存。

总之,生成器是Python中一个非常有用的特性,它们提供了一种惰性计算的方式,只在需要时才生成值,从而节省了内存和计算资源。通过生成器函数和生成器表达式,我们可以轻松地创建和使用生成器来处理迭代逻辑和大数据集。

三、访问生成器

使用for循环遍历生成器

首先,我们定义一个简单的生成器函数:

# 定义一个生成器函数,它逐个生成从0到4的数字  
def simple_generator():  for i in range(5):  yield i  # 使用yield关键字,使函数成为一个生成器  # 使用for循环遍历生成器  
for value in simple_generator():  print(f"For loop value: {value}")

运行结果

For loop value: 0  
For loop value: 1  
For loop value: 2  
For loop value: 3  
For loop value: 4

使用__next__()方法访问生成器

生成器对象本身也有__next__()方法,可以实现与next()函数相同的功能:

# 重新创建生成器对象  
gen = simple_generator()  # 使用生成器对象的__next__()方法获取下一个值  
print(f"__next__() value: {gen.__next__()}")  # 输出第一个值  
print(f"__next__() value: {gen.__next__()}")  # 输出第二个值  
print(f"__next__() value: {gen.__next__()}")  # 输出第三个值  # 当生成器耗尽时,继续调用__next__()会引发StopIteration异常  
try:  print(f"__next__() value: {gen.__next__()}")  # 输出第四个值  print(f"__next__() value: {gen.__next__()}")  # 尝试获取第五个值,会抛出异常  
except StopIteration:  print("Generator exhausted")

输出结果:

__next__() value: 0  
__next__() value: 1  
__next__() value: 2  
__next__() value: 3  
Generator exhausted

使用next()方法访问生成器

我们可以直接使用next()函数来获取生成器的下一个值:

# 重新创建生成器对象  
gen = simple_generator()  # 使用next()方法获取生成器的下一个值  
print(f"Next value: {next(gen)}")  # 输出第一个值  
print(f"Next value: {next(gen)}")  # 输出第二个值  
print(f"Next value: {next(gen)}")  # 输出第三个值  # 当生成器耗尽时,继续调用next()会引发StopIteration异常  
try:  print(f"Next value: {next(gen)}")  # 输出第四个值  print(f"Next value: {next(gen)}")  # 尝试获取第五个值,会抛出异常  
except StopIteration:  print("Generator exhausted")

运行结果:

Next value: 0  
Next value: 1  
Next value: 2  
Next value: 3  
Generator exhausted

使用send()方法

send()方法不仅可以获取生成器的下一个值,还可以向生成器发送一个值(通过yield表达式接收)。需要注意的是,首次启动生成器不能使用send(),而必须使用next()或__next__()。

# 定义一个接受send值的生成器函数  
def generator_with_send():  received = yield "Start"  # 第一个yield,此时received是None  while True:  received = yield received  # 后续yield,将接收到的值发送回去  # 创建生成器对象  
gen = generator_with_send()  # 启动生成器  
print(f"First value: {next(gen)}")  # 必须首先使用next()启动  # 使用send()发送值并获取生成器的下一个值  
print(f"Send value: {gen.send('First send value')}")  # 发送值并获取"First send value"  
print(f"Send value: {gen.send('Second send value')}")  # 再次发送值并获取"Second send value"  # 为了避免无限循环,我们在这里停止  
# 在实际应用中,可以根据条件在生成器内部控制循环的结束

输出结果:

# 定义一个接受send值的生成器函数  
def generator_with_send():  received = yield "Start"  # 第一个yield,此时received是None  while True:  received = yield received  # 后续yield,将接收到的值发送回去  # 创建生成器对象  
gen = generator_with_send()  # 启动生成器  
print(f"First value: {next(gen)}")  # 必须首先使用next()启动  # 使用send()发送值并获取生成器的下一个值  
print(f"Send value: {gen.send('First send value')}")  # 发送值并获取"First send value"  
print(f"Send value: {gen.send('Second send value')}")  # 再次发送值并获取"Second send value"  # 为了避免无限循环,我们在这里停止  
# 在实际应用中,可以根据条件在生成器内部控制循环的结束

输出结果:

First value: Start  
Send value: First send value  
Send value: Second send value

四、yield关键字的作用

yield关键字在生成器函数中有以下几个作用:

  • 返回一个值给调用者:每次调用next()方法或迭代生成器对象时,生成器函数会从上次离开的位置继续执行,直到遇到下一个yield语句,并返回该语句的值。
  • 暂停函数执行:当生成器函数执行到yield语句时,它会暂停执行,并保存当前的所有局部变量和状态。下次调用next()方法时,它会从上次暂停的位置继续执行。
  • 记忆状态:生成器能够记住上一次迭代时的状态,这使得它能够在多次迭代中保持内部状态的一致性。

五、生成器的优势

生成器具有以下几个优势:

  • 惰性计算:生成器只在需要时才计算下一个值,这可以节省内存和计算资源。
  • 节省内存:由于生成器一次只返回一个值,并且使用迭代器协议进行迭代,因此它们可以处理大数据集而不会耗尽内存。
  • 简化代码:生成器提供了一种简洁的方法来编写迭代逻辑,使得代码更加清晰和易于维护。

六、生成器的应用场景

生成器适用于以下场景:

  • 处理大数据集:当数据集非常大时,使用生成器可以避免一次性将所有数据加载到内存中。
  • 需要惰性计算的场景:当只需要处理数据集的一部分时,生成器可以按需生成值,而无需计算整个数据集。
  • 自定义迭代逻辑:当需要自定义迭代逻辑时,生成器提供了一种灵活的方式来实现这一点。

推荐阅读

Python基础

Python全网最全基础课程笔记(一)——基础入门
Python全网最全基础课程笔记(二)——变量
Python全网最全基础课程笔记(三)——所有运算符+运算符优先级
Python全网最全基础课程笔记(四)——基本数据类型
Python全网最全基础课程笔记(五)——选择结构+Python新特性Match
Python全网最全基础课程笔记(六)——循环结构
Python全网最全基础课程笔记(七)——列表,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(八)——字典,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(九)——集合,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(十)——元组,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(十一)——字符串所有操作,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(十二)——函数,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(十三)——作用域,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!

Flink入门到就业

2024年最新Flink教程,从基础到就业,大家一起学习–基础篇
2024年最新Flink教程,从基础到就业,大家一起学习–入门篇
2024年最新Flink教程,从基础到就业,大家一起学习–Flink集群部署
2024年最新Flink教程,从基础到就业,大家一起学习–flink部署和集群部署(从本地测试到公司生产环境如何部署项目源码)
2024年最新Flink教程,从基础到就业,大家一起学习–Flink运行架构底层源码详解+实战
2024年最新Flink教程,从基础到就业,大家一起学习–Flink DataStream API-第一篇+源码讲解

在这里插入图片描述

相关文章:

全网都在找的Python生成器竟然在这里!简单几步,让你的代码更简洁、更高效!

博客主页:长风清留扬-CSDN博客系列专栏:Python基础专栏每天更新大数据相关方面的技术,分享自己的实战工作经验和学习总结,尽量帮助大家解决更多问题和学习更多新知识,欢迎评论区分享自己的看法感谢大家点赞&#x1f44…...

插入排序,希尔排序,和归并排序

每一本数据结构和算法的教科书中,都不厌其烦的介绍了排序算法。不厌其烦的介绍10余种不同的排序。那么实际编程中用得到那么多排序算法吗?当然用不到。那么为什么全世界的教科书都这么写呢?显然是醉翁之意不在酒。 数组,是每个编…...

Prompt 模版解析:诗人角色的创意引导与实践

Prompt 模版解析:诗人角色的创意引导与实践 Prompt 模版作为一种结构化工具,旨在为特定角色——本例中的“诗人”——提供明确的指导和框架。这一模版详尽地描绘了诗人的职责、擅长的诗歌形式以及创作规则,使其能在自动化系统中更加精确地执…...

zookeeper选举kafka集群的controller

zookeeper选举kafka集群的controller目录 文章目录 zookeeper选举kafka集群的controller目录前言一、实操体验controller的选举二、模拟controller选举四、删除controller节点 前言 kafka集群的controller是kafka集群中一个有特殊作用的broker,负责整个kafka集群的…...

吉如一线段树:区间最值和历史最值

区间最值和历史最值 问题一 给定一个长度为 n n n 的数组 a a a , 实现以下三种操作 : 0 l r x : 将 a r r [ l ∼ r ] arr[l\sim r] arr[l∼r] 范围的每个数 v v v , 更新为 min ⁡ ( v , x ) \min (v, x) min(v,x) 1 l r : 查询 max ⁡ i l r a r r i \max_{il}^r ar…...

数据库常见的安全特性有哪些

数据库的安全特性主要包括以下几个方面,以确保数据的机密性、完整性和可用性: 1. 身份验证(Authentication) 数据库系统会通过身份验证来确定用户的身份,常见的方式有用户名/密码验证、基于证书的验证、多因素验证&a…...

Debezium日常分享系列之:Debezium 3.0.0.Final发布

Debezium日常分享系列之:Debezium 3.0.0.Final发布 Debezium 核心的变化需要 Java 17基于Kafka 3.8 构建废弃的增量信号字段的删除每个表的详细指标 MariaDB连接器的更改版本 11.4.3 支持 MongoDB连接器的更改MongoDB sink connector MySQL连接器的改变MySQL 9MySQL…...

MVCC(多版本并发控制)

目录 1.MVCC的工作原理2.MVCC的优点3.例子 MVCC(多版本并发控制)是一种用于数据库管理系统中实现并发控制的技术。它允许多个事务同时对数据库进行读写操作,而不会相互干扰,从而提高数据库系统的性能和可用性。MVCC通过为每个事务…...

低代码可视化-uniapp响应式数据data-代码生成器

在uniapp框架中,data 是一个核心的概念,它代表了组件或uniapp实例中的响应式数据。这些数据是组件状态的基础,uniapp会根据这些数据的变化来更新DOM,从而保持视图与数据的同步。 data 的特点 响应式:uniapp使用一种称…...

10.7学习

1.安全认证 ●Session 认证中最常用的一种方式,也是最简单的。存在多节点session丢失的情况,可通过nginx粘性Cookie和Redis集中式Session存储解决 ●HTTP Basic Authentication 服务端针对请求头中base64加密的Authorization 和用户名和密码进行校验。…...

基础算法之前缀和--Java实现(下)--LeetCode题解:-和为 K 的子数组 - 和可被 K 整除的子数组 -连续数组-矩阵区域和

这里是Themberfue 和为 K 的子数组 题目解析 返回子数组中所有元素的和等于给定k的个数。 算法讲解 这题好像是用滑动窗口解决,但其实不能,因为 nums 中的元素可能存在负数,就不能保证其单调性的性质。 用前缀和求也不易想到,…...

序列化与反序列化基础及反序列化漏洞(附案例)

参考文章: [web安全原理]PHP反序列化漏洞 - 笑花大王 - 博客园 (cnblogs.com) 一、概念 为了能有效的存储数据而不丢失数据的类型和内容,经常需要通过序列化对数据进行处理,将数据进行序列化后,会生成一个字符串,字符…...

Khronos:动态环境下时空度量语义SLAM的统一方法

Khronos: A Unified Approach for Spatio-Temporal Metric-Semantic SLAM in Dynamic Environments 原文 项目 引言: 人类居住环境通常是高度动态的,人、机器人和其他实体不断移动、互动和改变场景。对于机器人在这种情况下的操作,仅仅建立一…...

一个迷茫的25岁前端程序员的自述

作者:一尾流莺 一直听说程序员的危机在 35 岁,没想到我的危机从 25 岁就开始了。 我甚至不知道自己是不是 25 岁,也可能是 26 岁,或者 27 岁,1998 年的生日,按照 2023 - 1998 的算法就是 25,按…...

多文件并发多线程MD5工具(相对快速的MD5一批文件),适配自定义MD5 Hash I/O缓存。

自己写的多文件 MD5校验工具,一个文件开一个线程,有最大I/O 缓存设置,兼容读写MD5后缀文件。 共计91个文件,合计180G左右 12分钟左右,UI基本卡废,但程序没蹦,属于正常。 卡的原因是基本是用 I/O…...

Pikachu-url重定向-不安全的url跳转

不安全的url跳转 不安全的url跳转问题可能发生在一切执行了url地址跳转的地方。如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地,而又没有做判断的话就可能发生"跳错对象"的问题。 url跳转比较直接的危害是: …...

如何下载和安装CLion,图文详解

一、下载 登录JetBrains官网,下载最新版本的Clion,Clion目前没有社区版,都是专业版。 二、安装 1、启动Clion安装程序,下一步。 2、修改安装目录,下一步。 3、创建桌面快捷方式,更新PATH变量&#xff0…...

vue3导入本地图片2种实现方法

在<script setup>中使用import语法&#xff1a; <template><img :src"logo" alt"Logo"> </template><script setup> import logo from ./assets/logo.png; </script> 使用Vue的ref来动态地在<script setup>中…...

leetcode 刷题day36动态规划Part05 背包问题(完全背包、518. 零钱兑换 II、377. 组合总和 Ⅳ、70. 爬楼梯 (进阶))

完全背包 完全背包的每件商品都有无限个&#xff0c;和01背包的一不同主要体现在遍历顺序上。为了保证每个物品仅被添加一次&#xff0c;01背包内嵌的循环是从大到小遍历。而完全背包的物品是可以添加多次的&#xff0c;所以要从小到大去遍历。 518. 零钱兑换 II 思路&#…...

检查jar冲突,查找存在相同class的jar

写在前面 本文看下如何查找jar冲突&#xff0c;即查找哪些jar包中存在相同的class。如果是存在相同jar的不同版本&#xff0c;基本一眼就能看出来&#xff0c;然后结合maven的依赖关系将其剔除掉即可&#xff0c;但是当你遇到了有人手动拷贝某些class到jar包中导致冲突的情况时…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能

指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...

【java面试】微服务篇

【java面试】微服务篇 一、总体框架二、Springcloud&#xff08;一&#xff09;Springcloud五大组件&#xff08;二&#xff09;服务注册和发现1、Eureka2、Nacos &#xff08;三&#xff09;负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...

深入解析光敏传感技术:嵌入式仿真平台如何重塑电子工程教学

一、光敏传感技术的物理本质与系统级实现挑战 光敏电阻作为经典的光电传感器件&#xff0c;其工作原理根植于半导体材料的光电导效应。当入射光子能量超过材料带隙宽度时&#xff0c;价带电子受激发跃迁至导带&#xff0c;形成电子-空穴对&#xff0c;导致材料电导率显著提升。…...

SQL注入篇-sqlmap的配置和使用

在之前的皮卡丘靶场第五期SQL注入的内容中我们谈到了sqlmap&#xff0c;但是由于很多朋友看不了解命令行格式&#xff0c;所以是纯手动获取数据库信息的 接下来我们就用sqlmap来进行皮卡丘靶场的sql注入学习&#xff0c;链接&#xff1a;https://wwhc.lanzoue.com/ifJY32ybh6vc…...

二维数组 行列混淆区分 js

二维数组定义 行 row&#xff1a;是“横着的一整行” 列 column&#xff1a;是“竖着的一整列” 在 JavaScript 里访问二维数组 grid[i][j] 表示 第i行第j列的元素 let grid [[1, 2, 3], // 第0行[4, 5, 6], // 第1行[7, 8, 9] // 第2行 ];// grid[i][j] 表示 第i行第j列的…...