一、生成器的由来
生成器继承于迭代器,迭代器继承于可迭代对象,他是一个特殊的迭代器,拥有迭代器的所有特性
# 列表
list1 = [1,2,3,4,5,6]
# 列表生成式
list2 = [x for x in range(1,7)]
print(list1)
print(list2)
列表和列表生成器都无法解决内存受限的问题,列表中的所有数据都保存在内存中,以至于列表中的元素的太多了,当列表中的元素超过超过几十万甚至几百万,大量数据占用电脑内存,从而导致内存溢出,不利于我们后面的编程,所以要引用生成器
二、生成器定义
生成器是python中的一个对象(按照某种规律,来生成元素的对象),生成器不是列表,保存了产生元素的算法,同时会记录游标的位置(现在拿到第几个元素了),为了下次继续拿数据,而不是从头开始拿数据。可以通过一直调用next()方法获取值,这个对象不保存数据,每次调用会返回一个值,即做到了列表的好处,又不占用空间。
三、创建生成器
1、函数中使用了关键字yield,那这个函数就不再是一个普通的函数了,而是一个生成器函数
2、生成器函数调用时,不会执行函数内部的代码,会直接返回一个生成器对象
3、关键字yield的作用
是用来生成数据
yield data
第一种方式:类似通过列表生成式来创建(将列表转换为元组)
>>> list_1 = (x for x in range(1,10))
>>> print(list_1)
<generator object <genexpr> at 0x000001F9867982E0>
>>> print(type(list_1))
<class 'generator'>
>>>
generator:表示生成器
第二种方法:通过函数创建生成器(yield)
1、例如创建有限的斐波拉且数列
def test(number):
a,b,n = 0,1,0
while n < number:
yield b
a,b = b,(a+b)
n += 1
return 'done'
a = test(6)
print(a)
yield一般用于创建生成器,作用:返回后面变量(b)给生成器,而不是返回给函数的,b就是斐波拉且数列中的一个元素
a = test(6)
只要在函数中有yield关键字,那么当前这个函数是属于生成器中保存的算法,算法实现的功能就是生成b
print(a)
不会打印done
例如创建无限的斐波拉且数列,不能用for循环
def test(number):
a, b, n = 0, 1, 0
while n < number:
yield b
a, b = b, (a + b)
n += 1
return 'done'
a = test(6)
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
注意:yield:是没有返回值的,如果赋值的话会打印None
def test(number):
a, b, n = 0, 1, 0
while n < number:
num = yield b # 设置返回值
a, b = b, (a + b)
n += 1
print(num) # 输出None
return 'done'
a = test(6)
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
四、遍历生成器中的元素
第一种方法:next(生成器对象)
通过next(g),每调用一次next(),就会拿掉一个值(表达式中的第一个值),当已经遍历到生成器的结尾,会抛一个异常StopIteration。第4次调用next()的时候,生成器中已经没有数据了,继续调用会报错
第二种方法:for循环
通过for循环遍历,for循环不会抛出异常
for循环的打印结果为:4,5,6,7,因为调用了一次next(g),游标已经往下走了,
第三种方法:生成器对象next()
object内置的__next__,当已经遍历到生成器的结尾,会抛一个异常StopIteration
五、生成器中的方法
生成器比迭代器多了3个方法
1、close():
关闭生成器
生成3个元素后,生成器将不在生成对象了
报:StopIteration
2、send()
send():和next一样可以用来生成数据,可以往生成器内部传递数据(可以和生成器内部进行交互)
使用生成器时的注意:
1、不管使用next方法还是send方法,每次执行到yield时,都会暂停,并且将yield后面的值返回出来
2、send使用时,生成器内部必须处于yield暂停的位置(使用send之前,生成器至少是通过next去生成一次数据)
案例1
原因是,使用send之前没有通过next去生成一次数据
案例2
案例3:
定义一个可以使用send传入域名,自动生成一个在前面加上http://,在后面加上路径/user/login的url地址,生成器最多可以生成5个url,生成5条数据之后再去生成,则报错StopIteration
案例4:
实现一个可以根据姓名、电话、年领的生成器
可以根据send方法传入的值,来生成不同的数据
1 名字
2 电话
3 年领
执行逻辑
当number=2时,本轮循环已经结束了,开始下一轮循环,当开始下一轮循环时,number=2
3、throw()
在生成器中抛出异常,效果等同于raise
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具