python自学之《21天学通Python》(6)

news2025/1/18 7:42:01

第9章 迭代器、生成器与装饰器

迭代器、生成器与装饰器是Python语言中常用的语法形式。

迭代器的使用简化了循环程序的代码并可以节约内存,生成器的使用也可以节约大量的内存,特别是需要生成大量序列的对象时。迭代器是一种可以从其中连续迭代的一个容器,如前文所述,所有的序列类型都是可迭代的。而生成器则是函数中包含yield语句的一类特殊的函数。

装饰器的灵活性很强,可以为一个对象添加新的功能或者给函数插入相关的功能。在具体的程序设计中,可以灵活地设计出所需要的功能。

9.1 迭代器
Python中迭代器的使用是最为广泛的,本章以前代码中,凡是使用for语句,其本质上都迭代器的应用,本节主要介绍迭代器的概念、创建与应用。
9.1.1 迭代器概述
迭代器从表面上看是一个数据流对象或容器,当使用其中的数据时,每次从数据流中取一个数据,直到数据被取完,而且数据不会被重复使用。
从代码的角度看,迭代器是实现了迭代器协议方法的对象或类。迭代器协议方法主要是两个:
在这里插入图片描述
在这里插入图片描述
9.1.2 自定义迭代器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


>>> class Mylterator:
...     def __init__(self,x=2,xmax=100):
...         self.__mul,self.__x= x,x
...         self.__xmax = xmax
...     def __iter__(self):
...         return self
...     def __next__(self):
...         if self.__x and self.__x != 1:
...             self.__mul *= self.__x
...             if self.__mul <= self.__xmax:
...                 return self.__mul
...             else:
...                 raise Stoplteration
...         else:
...             raise Stoplteration
... 
>>> if __name__ == '__main__':
...     myiter = Mylterator()
...     for i in myiter:
...         print('迭代的数据元素为:', i)
... 
迭代的数据元素为: 4
迭代的数据元素为: 8
迭代的数据元素为: 16
迭代的数据元素为: 32
迭代的数据元素为: 64
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
  File "<stdin>", line 13, in __next__
NameError: name 'Stoplteration' is not defined
>>> 

9.1.3 内置迭代器工具
Python语言中,已经内建了一个用于产生迭代器的函数iter(),另外在标准库的itertools模块中还有丰富的迭代器工具,它们存在于itertools模块中。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

>>> class Counter:
...     def __init__(self,x=0):
...         self.x = x
... 
>>> counter = Counter()
>>> def used_iter():
...     counter.x += 2
...     return counter.x
... 
>>> for i in iter(used_iter,8):
...     print('本次遍历的数值', i)
... 
本次遍历的数值 2
本次遍历的数值 4
本次遍历的数值 6
>>> 

在这里插入图片描述
在这里插入图片描述

>>> import itertools
>>> for i in itertools.count(1, 3):
...     print(i)
...     if i >= 10:
...         break
... 
1
4
7
10
>>> x = 0
>>> for i in itertools.cycle(['a', 'b']):
...     print(i)
...     x += 1
...     if x >= 6:
...         break
... 
a
b
a
b
a
b
>>> list(itertools.repeat(3, 3))
[3, 3, 3]
>>> list(itertools.chain([1,3],[2,3]))
[1, 3, 2, 3]
>>> list(itertools.compress([1,2,3,4],[1,[],True,3]))
[1, 3, 4]
>>> list(itertools.dropwhile(lambda x:x>6, [8, 9, 1, 2, 8, 9]))
[1, 2, 8, 9]
>>> list(itertools.takewhile(lambda x:x>10, [18, 19, 1, 21, 8, 9]))
[18, 19]
>>> for its in itertools.tee([0,1],2):
...     for it in its:
...         print(it)
... 
0
1
0
1
>>> 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.2 生成器

使用生成器,可以生成一个值的序列用于迭代,并且这个值的序列不是一次生成的,而是使用一个,再生成一个,的确可以使程序节约大量内存。
9.2.1 生成器创建

>>> def myYield(n): #定义一个生成器(函数)
...     while n>0:
...         print("开始生成...:")
...         yield n #yield语句,用于返回给调用者其后表达式的值
...         print("完成一次....:")
...         n -= 1
... 
>>> if __name__ == '__main__':
...     for i in myYield(4): #for语句遍历生成器
...         print("遍历得到的值",i)
... 
开始生成...:
遍历得到的值 4
完成一次....:
开始生成...:
遍历得到的值 3
完成一次....:
开始生成...:
遍历得到的值 2
完成一次....:
开始生成...:
遍历得到的值 1
完成一次....:
>>> print()

>>> my_yield = myYield(3) #生成一个生成对象
>>> print('已经实例化生成器对象')
已经实例化生成器对象
>>> my_yield.__next__() #手工调用其特殊方法,获取序列中一个值
开始生成...:
3
>>> print('第二次调用__next__()方法: ')
第二次调用__next__()方法: 
>>> my_yield.__next__()
完成一次....:
开始生成...:
2
>>> 

【代码说明】代码自定义了一个递减数字序列的生成器,每次调用时都会产生一个从调用时所提供值为初始值的不断递减的数字序列。生成对象可以直接被for遍历,也可以手工进行遍历,手工的方法见上面代码最后两行。
在这里插入图片描述

9.2.2 深入生成器

如上节所述,生成器中包含yield语句,可以用for直接遍历;也可以手工调用其__next__()方法进行遍历。

yield语句是生成器中的关键语句,生成器在实例化时并不会立即执行,而是等待调用其__next__()方法才开始运行。并且当程序运行完yield语句后就会“吼(hold)住”,即保持其当前状态且停止运行,等待下一次遍历时才恢复运行。

如图9.3所示,程序运行结果中的空行之后的输出“已经实例化生成器对象”之前,已经实例化了生成器对象,但生成器并没有运行(没有输出“开始生成”)。当第一次手工调用__next__()方法之后,才输出“开始生成”,标志着生成器已经运行,而在输出“第二次调用__next__()方法:”之前并没有输出“完成一次”,说明yield语句运行之后就立即停止了。而第二次调用__next__()方法之后,才输出“完成一次…”,说明生成器的恢复运行是从yield语句之后开始运行的。(???)

yield语句不仅可以使函数成为生成器和返回值,还可以接受调用者传来的数值。但值得注意的是:第一次调用生成器时不能传送给生成器None以外的值,否则会引发错误。(???)

>>> def myYield(n):
...     while n>0:
...         rcv = yield n
...         n -= 1
...         if rcv is not None:
...             n = rcv
... 
>>> if __name__ == '__main__':
...     my_yield = myYield(3)
...     print(my_yield.__next__())
...     print(my_yield.__next__())
...     print('传给生成器一个值, 重新初始化生成器。')
...     print(my_yield.send(10))
...     print(my_yield.__next__())
... 
3
2
传给生成器一个值, 重新初始化生成器。
10
9
>>> 

在这里插入图片描述

9.2.3 生成器与协程

上节所述的运用send()方法来重置生成器的生成序列,其实也称为协程。协程是一种解决程序并发的方法。

如果采用一般的方法来实现生产者与消费者这个传统的并发与同步程序设计问题,则要考虑的问题还是比较繁杂的。但通过生成器实现的协程,解决这个问题就很简单。

>>> def consumer():
...     print('等待接收处理任务...')
...     while True:
...         data = (yield)
...         print('收到任务: ', data)
... 
>>> def producer():
...     c = consumer()
...     c.__next__()
...     for i in range(3):
...         print('发送一个任务...','任务%d' % i)
...         c.send('任务%d' % i)
... 
>>> if __name__ == '__main__':
...     producer()
... 
等待接收处理任务...
发送一个任务... 任务0
收到任务:  任务0
发送一个任务... 任务1
收到任务:  任务1
发送一个任务... 任务2
收到任务:  任务2
>>> 

在这里插入图片描述

9.3 装饰器

装饰器是一种增加函数或类的功能的简单方法,它可以快速地给不同的函数或类插入相同的功能。从本质上说,它是一种代码实现方式。

9.3.1 装饰器概述

为了给不同的函数或类插入相同的功能,在Python中可以使用非常优雅而简单的工具——装饰器。与其他高级语言相比,简化了代码,并且可以快速地实现所需要的功能。同时,它为函数或类对象增加功能也是透明的,对于同一函数,既可以添加简单的功能,也可以添加复杂功能,运用起来很灵活。而在调用被装饰的函数时,没有任何附加的东西,仍然像调用原函数或没有被装饰的函数一样。

在这里插入图片描述
在这里插入图片描述

9.3.2 装饰函数

用装饰器装饰函数,首先要定义装饰器,然后用定义的装饰器来装饰函数。

>>> def abc(fun):    #定义一个装饰器abc
...     def wrapper(*args, **kwargs):    #定义包装器函数
...         print('开始运行...')
...         fun(*args, **kwargs)    #调用被装饰函数
...         print('运行结束!')
...     return wrapper    #返回包装器函数
... 
>>> @abc    #装饰函数语句
... def demo_decoration(x):    #定义普通函数,被装饰器装饰
...     a = []
...     for i in range(x):
...         a.append(i)
...     print(a)
... 
>>> @abc
... def hello(name):    #定义普通函数(被装饰器装饰)
...     print('Hello',name)
... 
>>> if __name__ == '__main__':
...     demo_decoration(5)    #调用被装饰器装饰的函数
...     print()
... 
开始运行...
[0, 1, 2, 3, 4]
运行结束!

>>> if __name__ == '__main__':
...     demo_decoration(5)
...     print()
...     hello('John')    #调用被装饰器装饰的函数
... 
开始运行...
[0, 1, 2, 3, 4]
运行结束!

开始运行...
Hello John
运行结束!
>>> 

在这里插入图片描述
在这里插入图片描述

9.3.3 装饰类

>>> def abc(myclass):    #定义类装饰器
...     class InnerClass:    #定义内嵌类
...         def __init__(self, z=0):
...             self.z = 0
...             self.wrapper = myclass()    #实例化被装饰的类
...         def position(self):
...             self.wrapper.position()
...             print('z axis:', self.z)
...     return InnerClass    #返回新定义的类
...      
... 
>>> @abc
... class coordination:    #定义普通的类
...     def __init__(self, x=0, y=0):
...         self.x = x
...         self.y = y
...     def position(self):
...         print('x axis:', self.x)
...         print('y axis:', self.y)
... 
>>> if __name__ == '__main__':
...     coor = coordination()    #实例化被装饰的类
...     coor.position()
... 
x axis: 0
y axis: 0
z axis: 0
>>> 

在这里插入图片描述

9.4 小结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Shell 数组

数组中可以存放多个值。Bash Shell 只支持一维数组&#xff08;不支持多维数组&#xff09;&#xff0c;初始化时不需要定义数组大小&#xff08;与 PHP 类似&#xff09;。与大部分编程语言类似&#xff0c;数组元素的下标由 0 开始。Shell 数组用括号来表示&#xff0c;元素用…

教你如何巧妙化解SSRF漏洞攻击

SSRF是一种由攻击者构造请求&#xff0c;由服务端发起请求的安全漏洞。一般情况下&#xff0c;ssrf攻击的目标是外网无法访问的内部系统。简单来说就是利用服务器漏洞以服务器的身份发送一条构造好的请求给服务器所在内网进行攻击。 SSRF漏洞&#xff08; 服务器端请求伪造 &a…

【pandas】教程:9-如何轻松处理时间序列数据

Pandas 如何轻松处理时间序列数据 数据 本节使用的数据为 data/air_quality_no2_long.csv&#xff0c;链接为 pandas案例和教程所使用的数据-机器学习文档类资源-CSDN文库 import pandas as pd import matplotlib.pyplot as pltair_quality pd.read_csv("data/air_qua…

实战字节码-01-基础知识

开篇字节码是什么、做什么这类问题不在这里赘述&#xff0c;《实战字节码》系列旨在帮助没接触过字节码的人能够快速上手做应用开发&#xff0c;并构建字节码技术的知识骨架&#xff0c;所以不会系统地介绍字节码技术的方方面面&#xff0c;也尽量避免叙述理论和概念相关的东西…

【笔记:模拟CMOS集成电路】噪声——基本电路噪声性能(2)

【笔记&#xff1a;模拟CMOS集成电路】噪声——基本电路噪声性能&#xff08;2&#xff09;前言1 噪声——分析基础2 噪声——基本电路噪声性能2.1 MOS管噪声模型(1)电阻RG热噪声和沟道热噪声(2)衬底电阻热噪声(3)源极寄生电阻RS热噪声2.2常见组态的单级放大器噪声分析2.2.1 CS…

Python电影观众数量回归分析 随机森林 可视化 实验报告

实验报告&#xff1a;Python电影观众数量回归分析随机森林可视化-数据挖掘文档类资源-CSDN文库 前言 随着经济的发展和人民日益增长的美好生活需要的显著提升&#xff0c;看电影成为了人民群众在闲暇时光娱乐的重要途径。面对百花齐放的电影产业&#xff0c;哪些电影更能带动市…

OpenGL期末大作业——模拟太阳系(免费开源)

目录 一、项目介绍 二、配置与运行 三、项目地址 一、项目介绍 这是一个综合的openGL场景&#xff0c;模拟太阳系。场景中有光照&#xff0c;纹理等&#xff0c;并有丰富的视角控制&#xff0c;UI交互&#xff0c;比如WASD/IJKL键控制视角的移动等等。一个太阳系的场景&#…

大数据基础平台搭建-(五)Hive搭建

大数据基础平台搭建-&#xff08;五&#xff09;Hive搭建 大数据平台系列文章&#xff1a; 1、大数据基础平台搭建-&#xff08;一&#xff09;基础环境准备 2、大数据基础平台搭建-&#xff08;二&#xff09;Hadoop集群搭建 3、大数据基础平台搭建-&#xff08;三&#xff09…

Android今日头条平台隐私合规整改

头条应用管理平台开发者合规指引&#xff1a;https://open.oceanengine.com/labels/7/docs/1730079845340164头条审核合规的app&#xff0c;需要具备以下条件&#xff1a;用户协议弹窗抖音隐私政策&#xff08;模板示例&#xff09;&#xff1a;https://sf3-cdn-tos.douyinstat…

别告诉我你只知道waitnotify,不知道parkunpark???

目录 park&unpark wait,notify 和 park,unpark的区别 park unpark 原理 先调用park的情况 先调用park,在调用unpark的情况 先调用unpark,在调用park的情况 park&unpark park和unpark都是LockSupport的方法,park用于暂停当前线程的运行,而unpark用于恢复该线程的…

服务机器人“众生相”

在多种因素的共同作用下&#xff0c;早年间经常出现在科幻片中的机器人已然穿越荧屏来到了现实世界&#xff0c;为人们的日常生活增添了几分便利。比如&#xff0c;在家庭场景中&#xff0c;扫地机器人帮助人们解放双手&#xff1b;在餐饮场景中&#xff0c;送餐机器人为顾客提…

C语言--探索函数栈帧的创建与销毁

目录 为main函数开辟栈帧 创建变量 传参 为自定义函数开辟栈帧 返回 局部变量是怎么创建的&#xff1f;为什么局部变量的值是随机值&#xff1f;函数是怎么传参的&#xff1f;形参与实参的关系&#xff1f;函数怎么调用与返回&#xff1f; 我们用VS2013的环境进行探索…

Https为什么比Http安全?

Https是在Http之上做了一层加密和认证&#xff1b; 主要的区别是Https在TLS层对常规的Http请求和响应进行加密&#xff0c;同时对这些请求和响应进行数字签名。 Http请求的样式&#xff1a; 明文传输&#xff0c;通过抓包工具可以抓到 GET /hello.txt HTTP/1.1 User-Agent: c…

【三】Netty 解决粘包和拆包问题

netty 解决粘包和拆包问题TCP 粘包/拆包的基础知识粘包和拆包的问题说明TCP粘包/拆包 原因粘包和拆包的解决策略tcp 粘包/拆包 的问题案例大致流程如图:代码展示(jdk1.7)TimeServer 服务端启动类TimeServerHandler 服务端业务处理类TimeClient 客户端启动类TimeClientHandler 客…

Python入门注释和变量(2)

1.1输入 a input("请输入内容") print("您输入的内容是&#xff1a;{}".format(a)) 输入的内容会帮我们转换成字符串形式 2.1运算符 2.1.1算数运算符 以a 10 , b 20 为例进行运算 运算符描述实例加两个对象相加ab输出结果30-减得到负数或是一个数减…

You辉编程_有关boot

一、SpringBoot多环境配置 1.环境的配置信息 (1)application.properties #指定默认使用dev的配置 spring.profiles.activedev (2)application-dev.properties #开发环境 server.port8080 branchdev (3)application-prod.properties #测试环境 server.port8081 branchtest2…

【Nacos】Nacos介绍和简单使用

Nacos介绍及简单使用 Nacos介绍 Nacos是SpringCloudAlibaba架构中最重要的组件。Nacos是一个更易于帮助构建云原生应用的动态服务发现、配置和服务管理平台&#xff0c;提供了注册中心、配置中心和动态DNS服务三大功能。能够无缝对接SpringCloud、Spring、Dubbo等流行框架。 …

环境搭建 | MuMu模拟器 - Window10/11 系列

&#x1f5a5;️ 环境搭建 专栏&#xff1a;MuMu模拟器 - Window10/11 系列 &#x1f9d1;‍&#x1f4bc; 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; ✨ 个人主页&#xff1a;CoderHing的个人主页 &#x1f340; 格言: ☀️ 路漫漫其修远兮,吾将上下而求索☀️ …

FLV格式分析

1.FLV封装格式简介 FLV(Flash Video)是Adobe公司推出的⼀种流媒体格式&#xff0c;由于其封装后的⾳视频⽂件体积小、封装简单等特点&#xff0c;⾮常适合于互联⽹上使⽤。⽬前主流的视频⽹站基本都⽀持FLV。采⽤ FLV格式封装的⽂件后缀为.flv。 2.FLV封装格式分析 FLV封装格…

视频监视计划和设计软件丨IP Video System Design Tool功能简介

本软件提供快速轻松地设计现代视频监视系统之新方式 产品功能 • 降低寻找更好的视频摄像机位置的成本时&#xff0c;增加您的安全系统效能。 • 极短时间内&#xff0c;即可计算出精确的摄像机镜头焦距长度与视角。 • 使用2D和3D建模&#xff0c;检查每台摄像机的视野并寻…