5.迭代器和生成器
目录
一、迭代器
1.1可迭代对象
可迭代对象:内部含有'__iter__' 方法的对象。
# 获取一个对象的所有方法:dir()
s1 = 'asdsad'
print(dir(s1))
print('__iter__' in dir(s1))
优点:存储数据能直接显示,比较直观,
缺点:占内存,不能直接取值(除去索引,key以外)
通过for循环取值的时候,先将可迭代对象转换成迭代器,然后进行取值。
1.2迭代器
迭代器:内部含有'Iter'方法并且含有'next'方法的对象就是迭代器。
str list tuple dict set range 文件句柄 中只有文件句柄是迭代器,剩下的那些数据类型都是可迭代对象。
# 可通过,下列2个print的结果都返回True时才是迭代器
l1 = [1,2,3,4]
print('__iter__' in l1 )
print('__next__' in l1)
1.3可迭代对象转化成迭代器
l1 = [1, 2, 3, 4, 5, 6]
obj = l1.__iter__()
# 或者 obj=iter(l1) print(obj)
1.4迭代器取值
可迭代对象是不可以一直迭代取值的(除去用索引,切片以及Key),转化成迭代器就可以利用__next__()进行取值
l1 = [1, 2, 3,]
obj = l1.__iter__() # 或者 iter(l1)
# print(obj) # 返回一个地址
ret = obj.__next__()
print(ret)
ret = obj.__next__()
print(ret)
ret = obj.__next__()
print(ret)
ret = obj.__next__() # StopIteration
迭代器利用next取值,一个next对应一个值,如果迭代器里的值取完了,还要next就会报StopIteration错误。
1.5迭代器的小例子:while模拟for循环
l1 = [1, 2, 3, 4, 5]
# 1 将可迭代对象转化成迭代器
obj = iter(l1)
# 2,利用while循环,next进行取值
while 1:
# 3,利用异常处理终止循环
try:
print(next(obj))
except StopIteration:
break
迭代器的优点:
-
节省内存,迭代器在内存中只占用一条数据的空间,上一条数据next后所占内存就被释放了,然后再胡加载当前数据,这也是python把文件句柄设置为迭代器的原因。
-
惰性机制
next一次只取一个值
迭代器缺点:
- 不够直观
- 只能一直向后取值
二、生成器
2.1什么是生成器?
生成器本质就是迭代器,不同的是迭代器是python提供的,生成器要自己写。
2.2构造生成器
构造生成器的三种方式:
- 自己写的生成器函数
- 生成器推导式
- python内置函数或者模块提供
生成器函数:
return和yield的区别
- return 结束函数,并且返回值
- yield 只要函数中有yield就是生成器函数,生成器函数中可以写多个yield
- 生成器中可以有多个yield,yield不会结束生成器函数,一个yield对应一个next
def get_func():
li = []
for i in range(1, 5001):
li.append(f'{i}')
# 节省内存
def get_func():
for i in range(1, 5001):
yield f'{i}'
ret = get_func()
for i in range(222):
print(next(ret))
# 把列表变成迭代器
def func():
l1 = [1, 2, 3, 4, 5]
yield from l1 # 将l1变成了迭代器
ret1 = func()
print(next(ret1))
print(next(ret1))
yield from的简单应用:他后面可以加可迭代对象也可以是迭代器或生成器。
# 使用yield
s1 = 'an'
li = [1,2,3,4]
dic = {'name': 'cn', 'age':11}
dict1 =
def get_yield(*args):
for item in args:
for i in item:
yield i
print(list(get_yield(s1, li, dic)))
# ['a', 'n', 1, 2, 3, 4, 'name', 'age']
# 使用yield from
生成器的使用
这里的g1和g2是空的。
def func():
print(111)
yield 222
g = func() # 生成器
g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g)) # 回取出func中的数据,打印111,获取222
print(list(g1)) # 获取g1的数据,g1的数据来源是g,但是g已经取完了,g1也就没有数据了
print(list(g2)) # 和g1同理
生成器函数() -->返回的是一个地址
# 列表推导式习题
# 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表
# 输出[(0, 1), (0, 3), (0, 5), (2, 1), (2, 3), (2, 5), (4, 1), (4, 3), (4, 5)]
# print([(x, y) for x in range(0,6,2) for y in range(1,6,2)])
三、推导式
3.1列表推导式
- 循环模式:[ 变量(加工后的变量) for 变量 in iterable ]
- 筛选模式:[ 变量(加工后的变量) for 变量 in iterable if 条件 ]
优点:
- 可利用简单的代码构建比较复杂有规律的列表
- 也可以对列表中的一些元素进行筛选
# 循环模式
l1 = [i for i in rang(1, 11)]
l2 = [i**2 for i in range(10)]
# 筛选模式
# 30以内的被3整除
# print([i for i in range(0, 31) if i%3 == 0])
# 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
l1 = ['barry', 'ab', 'an', 'qwers', 'qwepopo']
# print([i.upper() for i in l1 if len(i) >= 3 ])
3.2生成器表达式
与列表推导式的写法几乎一模一样,也有筛选模式,循环模式,多层循环构建。写法上只有一个不同:
[] 换成 ()
列表的推导式和生成器的区别
- 写法上的区别:[] ()
- iterable iterator 可迭代对象和可迭代对象上的区别
生成器表达式和列表推导式的区别:
- 列表推导式比较耗内存,所有数据一次性加载到内存。而.生成器表达式遵循迭代器协议,逐个产生元素。
- 得到的值不一样,列表推导式得到的是一个列表.生成器表达式获取的是一个生成器
- 列表推导式一目了然,生成器表达式只是一个内存地址。
3.3其他推导式
字典推导式
lst1 = ['an','bn','cn']
lst2 = ['aa','bb','cc']
dic = {lst1[i]:lst2[i] for i in range(len(lst1))}
print(dic) # -->{'an': 'aa', 'bn': 'bb', 'cn': 'cc'}
集合推导式
lst = [1,2,3,4,5,6,7]
s = {abs(i) for i in lst}
print(s)
集合推导式可以帮我们直接生成一个集合,集合的特点;无序,不重复 所以集合推导式自带去重功能
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗