Python 可迭代对象(Iterable)、迭代器(Iterator)与生成器(generator)之间的相互关系

news/2024/4/29 22:48:12/文章来源:https://blog.csdn.net/lbj1260200629/article/details/128261118

1、迭代

通过重复执行的代码处理相似的数据集的过程,并且本次迭代的处理数据要依赖上一次的结果继续往下做,上一次产生的结果为下一次产生结果的初始状态,如果中途有任何停顿,都不能算是迭代。

# 非迭代例子
n = 0
while n < 3:print('hello world')n += 1
hello world
hello world
hello world
# 迭代例子
n = 0
while n < 3:print('第%s次 hello world'%(n+1))n += 1
第1次 hello world
第2次 hello world
第3次 hello world

前者循环内3次输出" Hello world",输出的数据不依赖上一次的数据,因此不是跌代。而后者的循环内打印的3次数据都上一次循环的影响,所以是迭代。

2、容器 container

容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用 in, not in关键字判断元素是否包含在容器中。

  • 从字面上理解,容器基本上可以包含其他类型对象(如列表、元组、字典等)作为元素的对象;在 Python 常见的数据类型中几乎所有的数据类型(字符串除外)都能包含其它类型的对象;

  • 容器仅仅只是用来存放数据的,我们平常看到的 l = [1,2,3,4] 等等,表面上我们可以直接从列表容器中取出元素,但事实上容器并不提供这种能力,而是可迭代对象赋予了容器这种能力。

3、可迭代对象(Iterable)

3.1 基本概念

可迭代对象并不是指某种具体的数据类型,它是指存储了元素的一个容器对象,且容器中的元素可以通过__iter__( )方法或__getitem__( )方法访问。

  • Python实现一个通用的外部可以访问可迭代对象内部数据的接口:

    • __iter__()方法的作用是让对象可以用 for ... in 循环遍历
    • __getitem__( )方法是让对象可以通过“实例名[index/key]”的方式访问实例中的元素
  • 一个可迭代对象是不能独立进行迭代的,Python中,迭代是通过 for ... in 来完成的。凡是可迭代对象都可以直接用 for...in 循环访问,这个语句其实做了两件事:第一件事是调用 __iter__() 获得一个可迭代器,第二件事是循环调用__next__()

3.2 判断一个对象是不是可迭代对象

可以使用 isinstance() 判断一个对象是否是 Iterable 对象

from collections import Iterableclass MyDataType1:# 自定义的数据类型1def __iter__(self):passclass MyDataType2:# 自定义的数据类型2pass# 自定义的数据类型实例化
mydatatype1 = MyDataType1()
mydatatype2 = MyDataType2()data_info = {"字典":{},  "列表":[],  "字符串":'abc',"元祖":(1,),"集合":{1,},"MyDataType1": mydatatype1, "MyDataType2": mydatatype2, "数字":100,"boolen":True, "None":None}
for key,value in data_info.items():result = isinstance(value, Iterable)if result:print(f"{key} is Iterable")else:print(f"{key} is not Iterable")
字典 is Iterable
列表 is Iterable
字符串 is Iterable
元祖 is Iterable
集合 is Iterable
MyDataType1 is Iterable
MyDataType2 is not Iterable
数字 is not Iterable
boolen is not Iterable
None is not Iterable

结合上述代码发现,添加了__iter__方法的 MyDataType1 对象已经是一个可迭代对象啦!!!

3.3 __iter__()函数与next()函数

  • iter 函数是让对象可以用 for ... in 循环遍历,即将对象转变为迭代器。
  • next 函数要和iter() 函数一起使用,不断使用next()函数来获取下一条数据(for 循环实现的原因)。
# 没有 iter 时,next 能使用
li = [11, 22, 33, 44, 55]
next(li)
---------------------------------------------------------------------------TypeError                                 Traceback (most recent call last)<ipython-input-4-b5d17e146774> in <module>1 # 没有 iter 时,next 能使用2 li = [11, 22, 33, 44, 55]
----> 3 next(li)TypeError: 'list' object is not an iterator
li = [11, 22, 33, 44, 55]
li = iter(li) # iter()函数实际上就是调用了可迭 代对象的 __iter__ 方法。
next(li)
11

4、迭代器(Iterator)

4.1 基本概念

迭代器可以看作是一个特殊的对象,每次调用该对象时会返回自身的下一个元素,从实现上来看,一个迭代器对象必须是定义了__iter__()方法和next()方法的对象。

  • Python 的 Iterator对象 表示的是一个数据流,可以把这个数据流看做是一个有序序列,但不能提前知道序列的长度,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算;
  • Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误;
  • 所有的 Iterable 可迭代对象均可以通过内置函数 iter()来转变为迭代器 Iterator。
  • 优点:节约内存(循环过程中,数据不用一次读入,在处理文件对象时特别有用,因为文件也是迭代器对象)、不依赖索引取值、实现惰性计算(需要时再取值计算);
  • 缺点: 迭代器使用上存在限制:只能向前一个个地访问数据,已访问数据无法再次访问、遍历访问一次后再访问无数据
# 不能提前知道迭代器的长度
li = iter([11, 22]) 
print(len(li))
---------------------------------------------------------------------------TypeError                                 Traceback (most recent call last)<ipython-input-6-0f3ba65b9307> in <module>1 # 不能提前知道迭代器的长度2 li = iter([11, 22])
----> 3 print(len(li))TypeError: object of type 'list_iterator' has no len()
# next 访问直至出现 StopIteration
li = iter([11, 22]) 
print(next(li))
print(next(li))
print(next(li))
11
22
---------------------------------------------------------------------------StopIteration                             Traceback (most recent call last)<ipython-input-7-3d729d10b8b7> in <module>3 print(next(li))4 print(next(li))
----> 5 print(next(li))StopIteration: 
# for 循环访问
li = iter([11, 22])
for i in li: print(i)
11
22

4.2 如何判断一个对象是否是迭代器

可以使用 isinstance() 判断一个对象是否是 Iterator 对象

from collections import Iteratorfor key,value in data_info.items():result = isinstance(value, Iterable)if result:print(f"{key} is Iterable  ", end=' ')else:print(f"{key} is not Iterable  ", end='')if isinstance(value, Iterator):print(f"is Iterator")else:print(f"is not Iterator")
字典 is Iterable   is not Iterator
列表 is Iterable   is not Iterator
字符串 is Iterable   is not Iterator
元祖 is Iterable   is not Iterator
集合 is Iterable   is not Iterator
MyDataType1 is Iterable   is not Iterator
MyDataType2 is not Iterable  is not Iterator
数字 is not Iterable  is not Iterator
boolen is not Iterable  is not Iterator
None is not Iterable  is not Iterator
class MyIterator:def __iter__(self):passdef __next__(self):pass
myiterator = MyIterator()
print(isinstance(myiterator, Iterable)) 
print(isinstance(myiterator, Iterator))
True
True

我们发现:

  • 一个实现了 __iter__() 方法和 __next__() 方法的对象,才是迭代器。
  • 一个对象是可迭代对象,但是不一定是迭代器;一个迭代器对象一定是可迭代对象。

5、生成器 (generator)

在 Python 中,使用了 yield 的函数被称为生成器。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

调用一个生成器函数,返回的是一个迭代器对象。

5.1 创建生成器的方式1:

# 第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )
L = [ x*2 for x in range(5)]
print(L) G = ( x*2 for x in range(5))
print(G)
[0, 2, 4, 6, 8]
<generator object <genexpr> at 0x10c02fb48>

创建 L 和 G 的区别仅在于最外层的 [ ] 和 ( ) , L 是一个列表,而 G 是一个生成器。

我们可以直接 打印出列表L的每一个元素,而对于生成器G,我们可以按照迭代器的使用方法来使用,即可以通 过next()函数、for循环、list()等方法使用。

5.2 创建生成器的方式2:

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的 for 循环无法实现的时候,还可以用函数来实现。

def fibonacci(n): # 生成器函数 - 斐波那契a, b, counter = 0, 1, 0while True:if (counter > n): returnyield aa, b = b, a + bcounter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生
f
<generator object fibonacci at 0x10c02f9e8>

5.3 访问生成器数据

# list 等方法
print("第1种方式访问:")
print(list(fibonacci(10)))# next 函数
print("第2种方式访问:")
f = fibonacci(10)
while True:try:print(next(f), end=" ")except StopIteration:print()break# for 循环
print("第3种方式访问:")
f = fibonacci(10)
for i in f:print(f"{i} ", end="")
第1种方式访问:
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
第2种方式访问:
0 1 1 2 3 5 8 13 21 34 55 
第3种方式访问:
0 1 1 2 3 5 8 13 21 34 55 
  • 使用了yield关键字的函数不再是函数,而是生成器。(使用了yield的函数就是生成器)
  • yield关键字有两点作用:
    • 保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起
    • 将yield关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用
  • 可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数)

5.4 生成器与生成器函数的判断区分

使用 isgeneratorfunction 判断一个函数是不是生成器函数;
使用 isinstance 和 types.GeneratorType 判断一个对象是不是生成器对象

from inspect import isgeneratorfunction 
import typesdef f(x):# 生成器函数yield x# 生成器对象
G = (x*2 for x in range(5))# 生成器函数的判断
print("f 函数是生成器函数?:", isgeneratorfunction(f))
print("f(5) 是生成器函数?:", isgeneratorfunction(f(5)))# 生成器对象的判断
print("f(5) 是生成器对象?:", isinstance(f(5), types.GeneratorType))
print(" G   是生成器对象?:", isinstance(G, types.GeneratorType))
f 函数是生成器函数?: True
f(5) 是生成器函数?: False
f(5) 是生成器对象?: TrueG   是生成器对象?: True

6、最后用一张图来表达他们之间的关系

jupyter

参考资料:

  • https://blog.csdn.net/LaoYuanPython/article/details/89609187
  • https://www.cnblogs.com/Aiyuqianer/p/14091062.html
  • https://www.runoob.com/python3/python3-iterator-generator.html
  • https://zhuanlan.zhihu.com/p/341439647

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

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

相关文章

java之注解的定义和使用

初识注解&#xff1a; 注解的概念&#xff1a; 注解是从JDK5.0开始引入的新技术&#xff0c;它不是程序本身&#xff0c;但是和注释有相同的作用&#xff0c;都能够对程序做出一定的解释&#xff0c;并且注解能够被其他编译器所读取 注解的格式&#xff1a; 注解是以“注释…

平均月薪15k+?自动化测试工程师?3个月教你从“点工”蜕变为“码农”

前言 一、自动化测试工程师平均收入【看图&#xff08;来自职友集&#xff09;】 基本收入都在15k左右&#xff0c;随着技术的越来越牛逼工资也就会越来越高。 我的职业生涯开始和大多数测试人一样&#xff0c;刚开始接触都是纯功能界面测试。那时候在一家电商公司做测试&…

[附源码]计算机毕业设计基于人脸识别的社区防疫管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

SSRF漏洞详解与利用

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是SSRF漏洞详解与利用。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未授权设…

迭代器和生成器

文章目录迭代器和生成器图解迭代器和生成器的关系迭代器容器生成器yield函数生成器表达式总结迭代器和生成器 图解迭代器和生成器的关系 图1-1​ 不管是生成器还是我们的容器&#xff0c;最终都是迭代器&#xff0c;使用next方法进行有规律的获取元素&#xff0c;不需要将元素…

五问补盲(二) | 补盲激光雷达,角分辨率真的是越小越好吗?

HiEV消息&#xff08;文&#xff1a;爱LiDAR的小飞哥&#xff09; 如何简单地判断一款补盲激光雷达的成像效果&#xff1f; 业界通常有几个指标&#xff1a;视场角大小、测距范围&#xff0c;以及角分辨率。 一款优秀的补盲激光雷达&#xff0c;通俗来说&#xff1a;既要看得…

rtl8221b+mcu,2.5g光纤收发器的开发备份

1、rtl8221b是一款2.5g的光电转换的phy 系统的构建如下 为了省成本&#xff0c;不用mac来对接其中的gmii接口直接接光模块 2、mdio和mdc由mcu的gpio来模拟&#xff0c;在csdn上有很多的文章来参考 mdio的参数如下 不想看英文可以参考下面的文章 MDIO(clause 22 与 clause 4…

微服务框架 SpringCloud微服务架构 微服务保护 31 限流规则 31.2 流控模式【关联】

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 微服务保护 文章目录微服务框架微服务保护31 限流规则31.2 流控模式【关联】31.2.1 流控模式31.2.2 流控模式 - 关联31.2.3 小结31 限流规则…

Python模块fileinput操作文件和目录操作总结

前言 之前介绍Python的 pathlib 模块可以有效的路径及文件查找等方便操作&#xff0c;本篇介绍一个相对 readlines() 获取文件内容更高效的用法 fileinput模块 对一个或者多个文件的内容迭代遍历&#xff08;类似文件操作的readlines()&#xff09;,但是返回的是迭代对象&…

【Linux】四、Linux 进程概念(三)|进程优先级|环境变量

目录 七、进程优先级 7.1 基本概念 7.1.1 什么是优先级 7.1.2 为什么存在优先级 7.1.3 Linux 优先级特点 7.2 查看系统进程 7.3 PRI 和 IN 7.4 查看进程优先级和更改进程优先级 7.5 其它概念 7.6 进程切换 八、环境变量 8.1 环境变量基本概念 8.2 常见环境变量 8…

English Learning - L1 站在高处建立灵魂 2022.12.5 周一

English Learning - L1 站在高处建立灵魂 2022.12.5 周一1.1 到底什么是语法1.2 为什么要学习语法口语分广义和狭义讲母语的人为啥不学语法&#xff1f;作为一名二语习得者口语中可不可以没有有语法&#xff1f;1.3 英语&#xff08;听说读写&#xff09;的核心金字塔理论关于词…

与图相关的一些矩阵

目录前言正文邻接矩阵(Adjacency matrix)度矩阵(Degree matrix)关联矩阵(Incidence matrix)拉普拉斯矩阵常规拉普拉斯矩阵拉普拉斯矩阵标准化前言 以无向图为例&#xff0c;介绍与图相关的各种矩阵。我们定义下面的图为 GGG&#xff1a; import networkx as nx import matplo…

redis cluster 集群安装

redis cluster 集群安装 redis集群方案 哨兵集群 如图&#xff0c;实际上还是一个节点对外提供服务&#xff0c;所以虽然是三台机器&#xff0c;但是还是一台机器的并发量&#xff0c;而且master挂了之后&#xff0c;整个集群不能对外提供服务 cluster集群 多个主从集群节点…

编写高质量代码 - 多线程和并发(2)

文章目录1. 使用线程异常处理器提升系统可靠性2. volatile不能保证数据同步3. 异步运算考虑使用Callable接口1. 使用线程异常处理器提升系统可靠性 我们要编写一个Socket应用&#xff0c;监听指定端口&#xff0c;实现数据包的接收和发送逻辑&#xff0c;这在早期系统间进行数据…

微信群营销方式微信群建群营销案例

今天我们以小区微信群营销为例&#xff0c;聊一聊具体的步骤和流程&#xff1a; 1、社群的建立&#xff0c;就是如何找到合适的小区&#xff0c;建立小区专属社群?因此&#xff0c;终端在做小区社群营销之前&#xff0c;需要先对当地所有的潜在小区做一个综合性的分析和评估&a…

ffmpeg库编译安装及入门指南(Windows篇)- 2022年底钜献

最近项目需要&#xff0c;使用了 ffmpeg 做摄像头视频采集和串流。这几天有点时间&#xff0c;打算把相关的一些知识记录分享一下。 在撰写本文时&#xff0c;我又在另外一台电脑上把 ffmpeg 重新安装了一遍&#xff0c;所以绝对真实靠谱&#xff01;如果你觉得文章写得还不错…

Linux消息中间件-RabbitMQ

Linux消息中间件-RabbitMQ 消息中间件 MQ简介 MQ 全称为Message Queue, 消息队列。是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息&#xff08;针对应用程序的数据&#xff09;来通信&#xff0c;而无需专用连接来链接它们。消息传递指的是程序之间通…

cef浏览器加载过程实测ILoadHandler和IRequestHandler

针对方法GetResourceRequestHandler获取资源请求过程中,会多次发生请求,不知道何时加载完的问题,IRequestHandler没有了OnResourceLoadComplete和OnBeforeResourceLoad方法,如何判断是否加载完。使用browser.isLoading并不能真正的判断。所以想到了 OnFrameLoadEnd OnFram…

Spring Cloud Alibaba-全面详解(学习总结---从入门到深化)

​​​​​​​ Spring Cloud Alibaba简介 什么是Spring Cloud Alibaba Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案。 此项目包含开发分布式应用微服务的必需组件&#xff0c;方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。 为…

微服务框架 SpringCloud微服务架构 微服务保护 31 限流规则 31.5 流控效果【排队等待】

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 微服务保护 文章目录微服务框架微服务保护31 限流规则31.5 流控效果【排队等待】31.5.1 流控效果【排队等待】31.5.2 案例31.5.3 总结31 限流…