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

python 生成器的作用

1. 生成器

参考:
https://www.cainiaojc.com/python/python-generator.html

1.1. 什么是生成器?

在 python 中,一边循环一边计算的机制,称为生成器:generator.

1.2. 生成器有什么优点?

1、节约内存。python在使用生成器时对延迟操作提供了支持。所谓延迟,是指在需要的时候才产生结果,而不是立即产生结果。这样在需要的时候才去调用结果,而不是将结果提前存储起来要节约内存。比如用列表的形式存放较大数据将会占用不少内存。这是生成器的主要好处。比如大数据中,使用生成器来调取数据结果而不是列表来处理数据,因为这样可以节约内存。
2、迭代到下一次的调用时,所使用的参数都是第一次所保留下的。

1.3. 在python中创建生成器

在python中,有两种创建生成器的方式:

1.3.1. 生成器表达式

类似与列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表。
使用列表推导,将会一次返回所有结果:

li=[i**2 for i in range(5)]
print(li)

运行结果:

[0, 1, 4, 9, 16]

将列表推导的中括号,替换成圆括号,就是一个生成器表达式:

li=(i**2 for i in range(5))
print(li)
for x in range(5):print(next(li))

运行结果:

<generator object <genexpr> at 0x7f124b6c8120>
0
1
4
9
16

注意:创建完成生成器后,可以使用next()来调用生成器的数据结果,每调用一次返回一个值,直到调用结束。调用结束后li中为空的,不在有任何值。要想使用它,只能重新创建新的生成器。(生成器表达式的第四行代码也可以改成:print(x).)

1.3.2. 生成器函数

常规函数定义,但是使用 yield 语句而不是 return 语句返回结果。yield 语句每次返回一个结果,但每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。我们下面来看一个例子。下面为一个可以无穷生产奇数的生成器函数。

def odd():n = 1while True:yield nn += 2odd_num = odd()
count = 0
for o in odd_num:if count >= 5:breakprint(o)count += 1

运行结果

1
3
5
7
9

上面的函数中,yield 是必备的,当一个普通函数中包含 yield 时,系统会默认为是一个 generator。

1.3.3. 生成器的两种方法

next() 和 send()
其中,next() 方法和 next 的作用是一样的。如下所示。

def fib(times):i=0 # 判断退出使用n=1 # 计算奇数使用while i < times:yield nn+=2i+=1f = fib(5)
for index in range(5):# print(next(f))print(f.__next__())

运行结果:

1
3
5
7
9

从上面的程序中可以看出,f.next() 和 next(f) 是作用是一样的。
下面再来看看send() 方法的使用。

def fib(times):i=0 # 判断退出使用n=1 # 计算奇数使用while i < times:# 添加变量 temptemp = yield nprint("fib", temp)n+=2i+=1f = fib(5)print(f.__next__())
print(f.send("haha"))
print(f.send("heihei"))

运行结果:

1
fib haha
3
fib heihei
5

从上面代码可以看出:使用 send() 时,必须在 yield 前面加上一个变量,并打印这个变量。在调用 send() 方法时其前面需要至少使用一次next() 或 next() 方法,因为生成器不可以在使用之前导入任何非 None 参数。由此可以知道,send() 是用来向生成器中导入参数并返回该参数的,与该参数一起返回的还有生成器中原先保存的数据。

1.3.4. 再看生成器

前面已经对生成器有了感性的认识,我们以生成器函数为例,再来深入探讨一下 python 的生成器:
1、语法上和函数类似:生成器函数和常规函数几乎是一样的。它们都是使用 def 语句进行定义,差别在于,生成器使用 yield 语句返回一个值,而常规函数使用 return 语句返回一个值。
2、自动实现迭代器协议:对于生成器,python 会自动实现迭代器协议,以便应用到迭代背景中(如for循环,sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的 next() 方法,并且,在没有值可以返回的时候,生成器自动产生 StopIteration 异常
3、状态挂起:生成器使用 yield 语句返回一个值。yield 语句挂起该生成器函数的状态,保留足够的信息,以便以后从它离开的地方继续执行。
生成器的唯一注意事项就是:生成器只能遍历一次

2. 迭代器

迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历位置的对象。迭代器只能往前不能后退。
1、什么是可迭代对象
集合数据类型,如 list 、tuple、dict、set、str 等
生成器和带 yield 的 generator function
2、如何判断对象可迭代?
from collections import Iterable
isinstance([ ],Iterable)

try:from collections.abc import Iterable
except ImportError:from collections import Iterable
#from collections import Iterable
print(isinstance([], Iterable))
print(isinstance("abcdef", Iterable))
print(isinstance((x for x in range(5)), Iterable))
print(isinstance(123456, Iterable))
print(isinstance(True, Iterable))

运行结果:

True
True
True
False
False

如上,命令行模式下,先导入Iterable模块,然后输入isinstance([ ],Iterable),括号中前面为待判断的对象,结果以布尔类型结束(True或False),列表是可迭代对象,因此返回True。注意:整数是不可迭代对象。

故障排除:
ImportError: cannot import name ‘Iterable’ from ‘collections’ (/home/lianap/anaconda3/lib/python3.10/collections/init.py)
参考:
https://blog.csdn.net/weixin_55201180/article/details/131345280
3、什么是迭代器呢?
**迭代器是可以被 next() 函数调用并不断返回下一个值的对象称为迭代器。**因此生成器是迭代器的子类,但是注意集合类型的可迭代对象不是迭代器。
iter() 函数:将可迭代对象转换成迭代器。

print(isinstance(iter([1, 2, 3, 4]), Iterable))
print(isinstance([1, 2, 3, 4], Iterable))

运行结果:

True
True

以上描述持怀疑态度。

3. 闭包

3.1. 什么是闭包

内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。
**闭包三要素:**嵌套函数,变量的引用,返回内部函数

# 定义一个嵌套函数(要素1)
def test(num):def test_in(num_in):# 内部函数引用外部函数的变量(非全局变量)(要素2)print("sum=%s"%(num + num_in))# 返回的结果可以被打印出来return num,num_in# 返回内部的函数(要素3)return test_in# 这里的rtn就是 test_in
rtn = test(10)
print(rtn)# 内部函数test_in传参
print(rtn(20))

运行结果:

<function test.<locals>.test_in at 0x7fbf353c9900>
sum=30
(10, 20)

3.2. 闭包的应用

#求一元一次方程的值,输入x,求y
def fun(a,b):     #其中a,b是固定的def fun_in(x):return a*x+breturn fun_in
f = fun(3,5)
print(f(1))    #每次输入不同的x值即可求出对应的y值
print(f(3))

运行结果:

8
14

上面的函数中,利用闭包来求一元一次方程的值,更方便,直接输入x的值即可求出对应的y的值。因为这利用了闭包可以记住外部函数的参数的特性。

4. 装饰器

4.1. 什么是装饰器(decorator)

装饰器其实就是一个闭包,把一个函数当作参数然后返回一个替代版函数。
装饰器有2个特性:
1、可以把被装饰的函数替换成其他函数
2、可以在加载模块时候立即执行
举例如下:
A、装饰器对无参数函数进行装饰:

# 装饰器本质就是一个闭包
# 将函数当做参数传进去
def deco(fun):def inner():print("你想进行的操作1")fun()print("你想进行的操作2")return inner# @deco 是一个“语法糖”
@deco
def test():print("test函数的操作")# 这个test已经被装饰了,不是原来的test
# 等同于
# rtn = deco(test)
# rtn()
test()

运行结果:

你想进行的操作1
test函数的操作
你想进行的操作2

4.2. 装饰器的功能有

1、引入日志
2、函数执行时间统计
3、执行函数前预备处理
4、执行函数后清理功能
5、权限校验等场景
6、缓存

4.3. 装饰器的分类

装饰器可分为:对有无参数函数进行装饰的装饰器,对有无返回值函数进行装饰的装饰器,组合起来一共有4种。
即:装饰器对无参数无返回值的函数进行装饰,装饰器对无参数有返回值的函数进行装饰,装饰器对有参数无返回值的函数进行装饰,装饰器对有参数有返回值的函数进行装饰。

4.3.1. 装饰器对无参数函数进行装饰

#定义函数:完成包裹数据
def makeBold(fn):def wrapped():return "<b>" + fn() + "</b>"return wrapped#定义函数:完成包裹数据
def makeItalic(fn):def wrapped():return "<i>" + fn() + "</i>"return wrapped@makeBold
def test1():return "hello world - 1"@makeItalic
def test2():return "hello world - 2"@makeBold
@makeItalic
def test3():return "hello world - 3"print(test1())
print(test2())
print(test3())

运行结果:

<b>hello world - 1</b>
<i>hello world - 2</i>
<b><i>hello world - 3</i></b>

上面这个例子是做网页的时候对字体进行设置,对 test1() 进行加粗,对 test2() 斜体处理,对 test3() 先斜体在加粗。
注意:对一个函数可以同时使用多个装饰器,装饰顺序由内而外。

4.3.2. 装饰器对有参数函数进行装饰

# 定义一个装饰器
def deco(func):def inner(a, b):    # 内部函数的参数必须和被装饰的函数保持一致print("添加的功能1")func(a, b)print("添加的功能2")return inner@deco
# 有参数的函数
def sum(a, b):print(a+b)sum(10,20)

运行结果:

添加的功能1
30
添加的功能2

当装饰器装饰有参数的函数时,装饰器内部的函数也必须带有和其相同的参数,因为被装饰的参数会被当成参数传进装饰器的内部函数中,如果两者的参数不一致,会报错。

4.3.3. 装饰器对不定长参数函数进行装饰

from time import ctime,sleep
#定义一个装饰器,装饰不定长参数函数
def deco(func):def inner(*args, **kwargs):print("%s called at the %s"%(func.__name__,ctime()))func(*args,**kwargs)return inner@deco
def test1(a, b, c):print(a+b+c)@deco
def test2(a, b):print(a+b)test1(10,20,30)
sleep(2)
test1(30,40,50)sleep(1)
test2(10,20)

运行结果:

test1 called at the Tue Nov 28 22:23:36 2023
60
test1 called at the Tue Nov 28 22:23:38 2023
120
test2 called at the Tue Nov 28 22:23:39 2023
30

4.3.4. 装饰器对有返回值的函数进行装饰

from time import ctime,sleep
#定义一个装饰器,装饰不定长参数函数
def deco(func):def inner(*args,**kwargs):print("%s called at the %s"%(func.__name__,ctime()))return func(*args,**kwargs)return inner
#上面的装饰器是一个万能的装饰器,因为它可以装饰任意一种函数
#包括有无参数函数和有无返回值函数@deco
def test():return "---ha--ha---"t = test()
print(t)

运行结果:

test called at the Tue Nov 28 22:26:46 2023
---ha--ha---

该装饰器是一个万能的装饰器,因为其可以用来装饰任何函数,包括有无参数函数和有无返回值函数。
参考:
https://blog.51cto.com/u_39029/6405726

相关文章:

python 生成器的作用

1. 生成器 参考&#xff1a; https://www.cainiaojc.com/python/python-generator.html 1.1. 什么是生成器&#xff1f; 在 python 中&#xff0c;一边循环一边计算的机制&#xff0c;称为生成器&#xff1a;generator. 1.2. 生成器有什么优点&#xff1f; 1、节约内存。p…...

第十五届蓝桥杯(Web 应用开发)模拟赛 2 期-大学组(详细分析解答)

目录 1.相不相等 1.1 题目要求 1.2 题目分析 1.3 源代码 2.三行情书 2.1 题目要求 2.2 题目分析 2.3 源代码 3.电影院在线订票 3.1 题目要求 3.2 题目分析 3.3 源代码 4.老虎坤&#xff08;不然违规发不出来&#xff09; 4.1 题目要求 4.2 题目分析 4.3 源代码 …...

图解系列--HTTPS,认证

确保 Web 安全的HTTPS 1.HTTP 的缺点 1.1.通信使用明文可能会被窃听 加密处理防止被窃听 加密的对象可以有这么几个。 (1).通信的加密 HTTP 协议中没有加密机制&#xff0c;但可以通过和 SSL&#xff08;Secure Socket Layer&#xff0c;安全套接层&#xff09;或TLS&#xff…...

element plus中表格的合计属性和例子

在 element plus 表格中&#xff0c;您可以使用 summary-method 属性来指定一个函数&#xff0c;计算表格中列的合计或平均值等。该函数应该返回一个对象&#xff0c;其中包含每个列的合计值。例如&#xff0c;如果您的表格数据是这样的&#xff1a; [{ name: John, age: 20, …...

计网Lesson1笔记

文章目录 几个简单概念计网的发展史阿帕网和RFCTCP/IP 协议互联网协议计网设计OSI 的七层架构TCP/IP 协议簇 几个简单概念 主机(host)&#xff1a;指单个计算机&#xff0c;比如PC&#xff0c;或者其他电子设备。端系统(end system)&#xff1a;指一块区域内的多个主机&#x…...

指针数组以及利用函数指针来实现简易计算器及typedef关键字(指针终篇)

文章目录 &#x1f680;前言&#x1f680;两段有趣的代码✈️typedef关键字 &#x1f680;指针数组&#x1f680;简易计算器的实现 &#x1f680;前言 基于阿辉前两篇博客指针的基础篇和进阶篇对于指针的了解&#xff0c;那么今天阿辉将为大家介绍C语言的指针剩下的部分&#…...

josef JZ-7Y-33静态中间继电器 电压DC220V 板前接线

系列型号&#xff1a; JZ-7Y-201X静态中间继电器&#xff1b;JZ-7J-201X静态中间继电器&#xff1b; JZ-7L-201X静态中间继电器&#xff1b;JZ-7D-201X静态中间继电器&#xff1b; JZ-7Y-201静态中间继电器&#xff1b;JZ-7J-201静态中间继电器&#xff1b; JZ-7L-201静态中…...

Java第二十章 ——多线程

本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 在这之前&#xff0c;首先让我们来了解下在操作系统中进程和线程的区别&#xff1a;   进程&#xff1a;每个进程都有独立的代码和数据空间&#xff08;进程上下文…...

【超强笔记软件】Obsidian实现免费无限流量无套路云同步

【超强笔记软件】Obsidian如何实现免费无限流量无套路云同步&#xff1f; 目录 一、简介 软件特色演示&#xff1a; 二、使用免费群晖虚拟机搭建群晖Synology Drive服务&#xff0c;实现局域网同步 1 安装并设置Synology Drive套件 2 局域网内同步文件测试 三、内网穿透群…...

【Linux小项目】实现自己的bash

0. bash原理介绍 bash实际上就是一个负责解析输入字符串工具. 我们需要做的事是这些: 手动分割出输入的字符串判断哪些变量是内建命令(自己执行),哪些命令是普通命令(创建子进程执行)实现的功能有: echo export cd 常规指令 输入、输出流重定向 #include<stdio.h> #i…...

客户案例:EDLP助力金融行业打造高效数据防泄露体系

客户背景 某金融机构是一家以金融科技为核心&#xff0c;致力于为客户提供全方位、智能化、便捷化金融服务的综合性企业。公司总部位于南京&#xff0c;业务范围覆盖全国&#xff0c;拥有强大的技术研发团队和优秀的业务精英&#xff0c;为客户提供全方位的金融服务解决方案。 …...

【JavaFX漏扫开发基础】stage窗口/模式/模态

文章目录 stage一、stage窗口二、stage窗口,模式,模态stage模式(5种样式)模态化窗口stage stage其实就是一个窗口,它啥也不是,打开所有windows的程序都会有一个窗口,这个窗口就是javafx里的stage。里面的内容不属于stage,stage就是一个窗口,就这么简单。 Stage is a…...

MySQL进阶知识:锁

目录 前言 全局锁 表级锁 表锁 元数据锁&#xff08;MDL&#xff09; 意向锁 行级锁 行锁 行锁演示 间隙锁/临界锁 演示 前言 MySQL中的锁&#xff0c;按照锁的粒度分&#xff0c;分为以下三类 全局锁&#xff1a;锁定数据库中的所有表。表级锁&#xff1a;每次操…...

linux下的工具---gdb

一、gdb简介 GDB,是The GNU Project Debugger 的缩写&#xff0c;是 Linux 下功能全面的调试工具。 GDB支持断点、单步执行、打印变量、观察变量、查看寄存器、查看堆栈等调试手段。 程序的发布方式有两种&#xff0c;debug模式和release模式 Linux gcc/g出来的二进制程序&am…...

ESP32-Web-Server编程-JS 基础 2

ESP32-Web-Server编程-JS 基础 2 概述 上节介绍了 JS 编程的基础。如前所述&#xff0c;在 HTML 中&#xff0c;可以通过下述 两种方式使用 JS 程序&#xff1a; 直接在 HTML 文件中通过 script 标签中嵌入 JavaScript 代码。通过 src 元素引入外部的 JavaScript 文件。 在…...

Java Web基础教程

Java Web基础教程 1. Servlet基础 1.1 什么是Servlet Servlet是JavaEE中的标准组件之一&#xff0c;专门用于处理客户端的HTTP请求。并且它必须依赖于Servlet容器&#xff08;Tomcat就是一个标准的Servlet容器&#xff09;才能运行。因为Servlet实例的创建和销毁都是由容器负…...

BUUCTF john-in-the-middle 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 注意&#xff1a;得到的 flag 请包上 flag{} 提交 密文&#xff1a; 下载附件&#xff0c;解压得到john-in-the-middle.pcap文件。 解题思路&#xff1a; 1、双击文件&#xff0c;打开wireshark。 看到很多http流…...

HashMap的死循环及数据覆盖问题

目录 一&#xff0c;HashMap 线程不安全的原因 二&#xff0c;HashMap 死循环问题 死循环发生的条件 死循环的具体过程 死循环执行步骤1 死循环执行步骤2 死循环执行步骤3 三&#xff0c;HashMap 数据覆盖问题 数据覆盖执行流程1 数据覆盖执行流程2 数据覆盖执行流…...

数据库数据恢复—MongoDB数据库文件拷贝出现错误的数据恢复案例

MongoDB数据库数据恢复环境&#xff1a; 一台Windows Server操作系统的虚拟机&#xff0c;虚拟机上部署有MongoDB数据库。 MongoDB数据库故障&检测&#xff1a; 在未关闭MongoDB服务的情况下&#xff0c;工作人员将MongoDB数据库文件拷贝到其他分区&#xff0c;然后将原数…...

2023年11月个人工作生活总结

本文为 2023 年 11 月工作生活总结。 研发编码 GIS 模仿了一些有名的地图服务商的网站&#xff0c;将离线地图页面做成全屏&#xff0c;对于大屏幕更加好友。再美化一下全区的边界和区内地域的边界。不过主要工作量还是绘制路线&#xff0c;而绘线作为内部工作&#xff0c;还…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...