迭代器、生成器

news/2025/3/25 2:54:38/文章来源:https://www.cnblogs.com/yi416/p/18204841

迭代器

【一】迭代器介绍

  • 迭代器就是用来迭代取值的工具,是重复反馈过程的程序
  • 目的是为了更加逼近我们想要的目标和结果
  • 每一次迭代得到的返回结果就是下一次迭代开始的初始值
num_list = [1,2,3,4,5,6]
count = 0
while count <len(num_list):# 每一次使用的索引位置就是上一次+1后的索引位置print(num_list[count])count += 11
2
3
4
5
6

【二】可迭代对象

【1】什么是可迭代对象

  • 可以通过列表的索引进行取值,但是如果一个数据没有索引的话
  • 必须找到一种可以用索引也可以不用索引的方法来取值

【2】八大基本数据类型

补充

生成可迭代对象的两种方式

iter()相当于__iter__(数据)

迭代器对象迭代的方法的两种方式

迭代器对象.__next__()next(迭代器对象)

数字类型

整数
age = 18
print(iter(age))
print(age.__iter__)
报错 	'int' object is not iterable浮点数
age = 18.5
print(iter(age))
print(age.__iter__)
报错	'float' object is not iterable

字符串类型

qwer = 'qewr'
print(iter(qwer))
print(qwer.__iter__)输出
<str_iterator object at 0x0000021D016BA740>
<method-wrapper '__iter__' of str object at 0x0000021D0165D3B0>

列表类型

list = [1,2,3,4,5,6]
print(iter(list))
print(list.__iter__)输出
<list_iterator object at 0x000001FA4D7097B0>
<method-wrapper '__iter__' of list object at 0x000001FA4D6B4E40>

字典类型

dict = {'q':'1','w':2}print(iter(dict))
print(dict.__iter__)输出
<dict_keyiterator object at 0x000001E457AED670>
<method-wrapper '__init__' of dict object at 0x000001E457AA1F40>

布尔类型

bool = True
print(iter(bool))
print(bool.__iter__)报错 	'bool' object is not iterable

元组类型

tuple = (1,2,3,4,5,6)print(iter(tuple))
print(tuple.__iter__)输出
<tuple_iterator object at 0x000001AE3656A740>
<method-wrapper '__init__' of tuple object at 0x000001AE36578940>

集合类型

set = {1,2,3,4,5,6}
print(iter(set))
print(set.__iter__)输出
<set_iterator object at 0x000001E74BFF2080>
<method-wrapper '__init__' of set object at 0x000001E74C026DC0>

【3】总结

能.__iter__不报错的就是可迭代类型 ————>可迭代对象

可迭代类型

字符串、列表、元组、集合、字典

不可迭代类型

整数、浮点数、布尔

【三】迭代器对象

【1】什么是迭代器对象

# 如果调用obj.__iter__()返回的是一个可迭代对象# 有的可迭代对象还有__next__()方法
# 迭代器对象实在可迭代对象(具有.__iter__()方法)的基础上具有.__next__()方法的对象

【2】八大基本数据类型(除了不可迭代)

(1)字符串

name = "qwer"
name_iter = name.__iter__()
print(name_iter)
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__()) # 会报错 most recent call last<str_iterator object at 0x00000202DE74A740>
q
w
e
r
第五行报错

(2)列表

name = [1,2,3,4,5,6]
name_iter = name.__iter__()
print(name_iter)
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())<list_iterator object at 0x0000026B66C3A740>
1
2
3
4
5

(3)字典

得到的是键

name = {'q':1,'w':'2','e':'3','r':'4'}
name_iter = name.__iter__()
print(name_iter)
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())<dict_keyiterator object at 0x000001C4B92DD670>
q
w
e
r

(4)元组

name = (1,2,3)
name_iter = name.__iter__()
print(name_iter)
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())<tuple_iterator object at 0x000001D9C593A740>
1
2
3

(5)集合

name = {1,2,3,4,5,6}
name_iter = name.__iter__()
print(name_iter)
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())<set_iterator object at 0x00000234968D2000>
1
2
3
4

【3】总结

具有__iter__() 和 __next__()方法的对象是可迭代对象
  • 在八大基本数据类型中,除了数字和布尔类型,其他都是迭代器对象

  • 迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器对象

  • 迭代器对象是同时具有上述两个方法的对象

  • 可迭代对象只需有第一个方法既是可迭代对象

【四】迭代器的优缺点

  1. 优点
    • 不使用索引取值(例如字典不支持索引取值)
    • 取到值后会保存当前状态,下次从当前位置开始继续取值
  2. 缺点
    • 除非取值取到尽头,否则永远不知道终止索引在哪里
    • 只能取一次记一次位置,下一次的其实位置是上一次的终止位置,想回到开头 回不去
    • 调用 next 取值的前提是 已经生成并且得到了一个迭代器对象 iter_obj
    • 迭代同一个对象只能重新创建
name = 'dr'
name_iter = name.__iter__()
print(next(name_iter))
print(next(name_iter))
name_iter = name.__iter__()	# 要重复取值必须重新创建迭代器对象
print(next(name_iter))d
r
d 

生成器

【一】什么是生成器

  • 生成器是一种特殊的迭代器

  • 在需要的时候给你数据,不需要就不会给数据

  • for循环 range(10) 可以把生成的数字取出来

  • 数据量过大的话 读取数据内存满,电脑卡死

  • 生成器 ---> 一次取...行 --->处理完这些数据后--->再取...行

例子 for i in fp:

【二】生成器的创建方式

【1】列表推导式

print([i for i in range(10)])
# 如果将列表生成式外面的列表换成元组,则会生成一个生成器对象
print((i for i in range(10)))[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
<generator object <genexpr> at 0x0000020E358F8430>

【2】yiled关键字

def add(i):yield i# add(2)进入到add函数,将原本的函数对象转换为生成器对象
res = add(2)
print(res)
# 想取值只能使用next来迭代取值
print(res.__next__())<generator object add at 0x00000155DB1E8430>
2
def add(i):# i = 1while True:yield i	 # 第一次nextres = add(1)
print(res)
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())
res = add(3)
print(res.__next__())<generator object add at 0x000001EFDF0CEAB0>
1
1
1
1
3

补充

在第一次调用生成器时,`yield`语句会在赋值操作符`=`的右边停下。考虑下面的代码:```python
def my_generator():x = yieldprint("Received:", x)gen = my_generator()
```当你执行`gen = my_generator()`时,生成器`my_generator`并没有开始执行。相反,它返回了一个生成器对象`gen`。此时,`my_generator`函数中的代码并没有运行。然后,当你调用`gen.__next__()`或`next(gen)`时,生成器才会开始执行。它会执行到`x = yield`这一行,但暂停在`yield`右边,等待接收一个值。这个值会被赋给`x`。因此,第一次调用`yield`语句时,生成器会停在赋值操作符`=`的右边。

【三】生成器案例

def outer():print("开始吃饭")while True:food = yield  # 等同于yield(food)print(f"做了{food},吃{food}")res = outer()
print(res)
print(res.__next__())
print(res.__next__())<generator object outer at 0x00000183F2538430>
开始吃饭
None	
做了None,吃None
None	# 原因是在生成器内部走完了上面代码,又回到了yield 没有返回值yield语句在生成器函数中充当了暂停和恢复执行的标记,同时也充当了返回值的功能。当生成器函数执行到yield语句时,它会暂停执行并将yield后面的表达式作为返回值返回给调用方。在上述代码中food为yield的后面的表达式

向生成器中传值

send() 传值后会再往下走一步

res = outer()
print(res)
print(res.__next__())
res.send('炒饼') # 向 yield 传值并且让生成器向下走一下
print(res.__next__())
res.send('炒饭')<generator object outer at 0x000002A8C99E8430>
开始吃饭
None
做了炒饼,吃炒饼
做了None,吃None
None
做了炒饭,吃炒饭

【四】装饰器 + 生成器

def init_iter(func):def inner(*args,**kwargs):# g 是得到的生成器对象g = func(*args,**kwargs)# 调用自己生成器往下走next(g)# 走回来的返回值返回出去return greturn inner@init_iter
def outer():print("开始吃饭")while True:# yield foodfood = yieldprint(f"做了{food},吃{food}")res = outer()
res.send('炒米粉')
res.send('炒fan')开始吃饭
做了炒米粉,吃炒米粉
做了炒fan,吃炒fan

【五】生成器内部修改可变数据类型

def init_iter(func):def inner(*args,**kwargs):# g 是得到的生成器对象g = func(*args,**kwargs)# 调用自己生成器往下走next(g)# 走回来的返回值返回出去return greturn inner@init_iter
def outer():print("开始吃饭")list = []while True:# yield foodfood = yieldlist.append(food)	因为没有退出循环,所以会把新值一直加到列表中print(f"做了{food},吃{food}")print(list)res = outer()
res.send('炒米粉')
res.send('炒fan')开始吃饭
做了炒米粉,吃炒米粉
['炒米粉']
做了炒fan,吃炒fan
['炒米粉', '炒fan']

【六】yield + next 搭配着使用

仿照循环自己构建循环函数

for i in range(5):print(i)
def my_range(start, stop, step):''':param start: 0:param stop: 5:param step: 1:return:'''print("start")while start < stop:yield startstart += stepprint("end")res = my_range(0, 5, 1)
print(res)  # <generator object my_range at 0x000002DF0361CBA0>
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())
# 这里会报错 ---> 没有可迭代的值可以被获取了
print(res.__next__())  # StopIteration
def init_iter(func):def inner(*args, **kwargs):try:generator = func(*args, **kwargs)next(generator)return generatorexcept StopIteration:passreturn innerdef range_(start, stop, step):while start < stop:yield startstart += step# for 循环内部做了异常捕获
for i in range_(0,5,1):print(i)def my_range(start, stop, step):def range_(start, stop, step):while start < stop:yield startstart += stepres = range_(start, stop, step)while True:try:print(res.__next__())except StopIteration:breakres = my_range(start=1, stop=5, step=1)
res0
1
2
3
4
1
2
3
4

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

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

相关文章

mysql报错:Lock wait timeout exceeded: try restadina transaction

这次是在Navicat上复制了一个表结构和数据准备备份一下,然后要用语句批量处理数据,结果导致项目上的更新操作报这个错误。原因是因为表中的数据量太大,复制表一时半会卡到那了。于是我在网上搜索了如下办法。尝试在数据库中杀死线程来终止复制表的操作。 SELECT * FROM info…

ASP.NET之JSONHelper操作

之前说到了Ext.Net中GridPanel行取值的问题(Ext.Net开发_GridPanel行选中取值),涉及到checkBox操作时,要留个心眼注意下取值的区别!返回值是Json格式。 现在用到了Json,就想自己也整一个Josn帮助类。在线帮助的资料很多,在巨人的身上东凑西凑也凑一个用用。   一、介绍…

Git:warning: CALF wilL be replaced by LF in xxxx 问题解决

warning: CALF wilL be replaced by LF in xxxx 问题解决办法 出现这个问题的原因是像缓存区中提交文件时出现的 原因: windows中的换行符为 CRLF,而在Linux下的换行符为LF,所以在执行add . 时出现提示 也就是, 工作区的文件都应该用 CRLF 来换行。如果 改动文件时引入了 …

密码爆破ssh与ftp服务(finish)

密码爆破ssh与ftp服务 使用工具九头蛇(hydra) ssh 环境配置 win10 安装sshd服务端在cmd命令行使用 net start sshd 命令启动服务kali 打开终端查看是否开启ssh服务 nmap -sV -T4 -p- [kali的ip] 先创建一个用户名字典username.txt,把经常用的用户名写入到字典中 touch usern…

Obsidian第三方插件下载

一、从Obsidian插件市场下载 使用第三方插件的第一步是关闭安全模式。点击“浏览”,搜索需要的插件名称。在这里输入名称搜索。点击安装。点击启用。必要时要使用魔法。 替代方法proxy-github二、从别的地方下载的插件 首先了解一下obsidian插件的基本构成,主要包括下面的文件…

鸿蒙4.2小版本大亮点,鸿蒙5.0也不远了

混合应用开发技术,特别是结合小程序和原生技术,为鸿蒙应用开发带来了显著的优势。首先,它简化了开发流程,使开发者能够迅速创建出高质量的应用程序。这不仅缩短了开发周期,还提升了应用的整体性能和用户体验。上个月,市场上迎来了华为鸿蒙系统4字开头的小升级,版本来到了…

JPA和Hibernate的乐观锁与悲观锁

哈喽,大家好,我是木头左!JPA和Hibernate的乐观锁和悲观锁 乐观锁 乐观锁是一种假设资源不会被冲突影响的并发控制策略。它假设多个事务在同一时间内不会发生冲突,因此不需要加锁。当事务提交时,如果检测到数据发生了改变,就会抛出异常,让开发者决定如何处理这个冲突。 在…

树形DP

树形 DP 即在树上进行的 DP。 常见的两种转移方向:父节点 \(\rightarrow\) 子节点:如求节点深度,\(dp_u = dp_{fa} + 1\) 子节点 \(\rightarrow\) 父节点:如求子树大小,\(dp_u = 1 + \sum dp_v\)习题:P5658 [CSP-S2019] 括号树暴力 本题 \(n\) 小的数据点保证为链,直接枚…

DBever SQL编辑器的高级应用:如何用变量快速查询

哈喽,大家好,我是木头左!一、DBever SQL编辑器简介 DBever是一款数据库管理工具,它支持多种数据库,如MySQL、SQL Server、Oracle等。其中,它的SQL编辑器功能非常强大,可以让更方便地进行SQL语句的编写和执行。今天,就来探讨一下DBever SQL编辑器中如何使用变量的方式。…

EDP .Net开发框架--自动化日志

EDP是一套集组织架构,权限框架【功能权限,操作权限,数据访问权限,WebApi权限】,自动化日志,动态Interface,WebApi管理等基础功能于一体的,基于.net的企业应用开发框架。通过友好的编码方式实现数据行、列权限的管控。平台下载地址:https://gitee.com/alwaysinsist/edp…

power 740 p740 连接远程管理模块

https://111.111.111.111/The connection for this site is not secure 111.111.111.111 uses an unsupported protocol.Try:Search the web for 111.111.111.111ERR_SSL_VERSION_OR_CIPHER_MISMATCHEdge 浏览器:https://blog.csdn.net/weixin_44904239/article/details/13096…

power 740 连接远程管理模块

https://111.111.111.111/The connection for this site is not secure 111.111.111.111 uses an unsupported protocol.Try:Search the web for 111.111.111.111ERR_SSL_VERSION_OR_CIPHER_MISMATCHEdge 浏览器:https://blog.csdn.net/weixin_44904239/article/details/13096…