python生成器

生成器

前言

使用列表推导的前提是将数据全部加载到内存,若是数据量太大的时候,比如有几十万条,那么占用内存和使用率会特别大,但是若是在整个数据集中只使用很少部分,那么其他空间就浪费掉了,生成器使列表解析得到加强,可以在循环的时候动态生成下一个元素。

1.创建生成器

创建生成器最简单的方法就是将列表的推导式改成小括号

list1 = [1,2,3,4,5,6,7,8,9,10]
data = [i for i in list1 if i % 2 == 0]
print('推导式获取偶数值:',data)

data = (i for i in list1 if i % 2 == 0)
print('[]变成()得到的生成器:',data)

print("获取生成器中第1个值",next(data))
print("获取生成器中第2个值",data.__next__())
推导式获取偶数值: [2, 4, 6, 8, 10]
[]变成()得到的生成器: <generator object <genexpr> at 0x00000271E03C9148>
获取生成器中第1个值 2
获取生成器中第2个值 4

这个列子,生成的最后结果是一次性得到的,使用生成器得到的结果是每次调用next或者__next__的魔法方法临时生成的,这就是为什么生成器能够应对大量数据的列表迭代的原因。

在使用next的方式获取值,在生成最后一个元素的时候,继续调用next,会触发异常。

print("获取生成器的第1个值:",next(data))
print("获取生成器的第2个值:",data.__next__())
print("获取生成器的第1个值:",next(data))
print("获取生成器的第1个值:",next(data))
print("获取生成器的第1个值:",next(data))
print("获取生成器的第1个值:",next(data))

获取生成器的第1个值: 6
获取生成器的第2个值: 8
获取生成器的第1个值: 10



---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-10-faed4bd43b80> in <module>
      2 print("获取生成器的第2个值:",data.__next__())
      3 print("获取生成器的第1个值:",next(data))
----> 4 print("获取生成器的第1个值:",next(data))
      5 print("获取生成器的第1个值:",next(data))
      6 print("获取生成器的第1个值:",next(data))


StopIteration: 

解决方式,可以使用for循环

list1 = [1,2,3,4,5,6,7,8,9,10]
data = [i for i in list1 if i % 2 == 0]
for i in data:
    print('当前元素是:',i)
当前元素是: 2
当前元素是: 4
当前元素是: 6
当前元素是: 8
当前元素是: 10

2.yield关键字

yield关键字可以创建生成器,调用get_list方法得到的是一个生成器实例,在get_list方法中,使用yield返回i值。m

list2 = [1,2,3,4,5,6,7,8,9,10]
def get_list():
    for i in list2:
        if i % 2 == 0:
            print('当前元素为:',i)
            yield i
            
gen = get_list()
for j in gen:
    print('当前获取的值:',j)
    print('--'*30)
当前元素为: 2
当前获取的值: 2
------------------------------------------------------------
当前元素为: 4
当前获取的值: 4
------------------------------------------------------------
当前元素为: 6
当前获取的值: 6
------------------------------------------------------------
当前元素为: 8
当前获取的值: 8
------------------------------------------------------------
当前元素为: 10
当前获取的值: 10
------------------------------------------------------------

整个循环的逻辑
每次执行到yield,退出get_list方法,然后执行第13行代码,当本次循环结束是,又到达yield退出的位置,接着完成自身循环。

3.将值传到生成器

生成器可以将方法内部的值传出来,也可以从外部将值传递到生成器。send与next方法都会触发生成器的执行,不同的是send方法可以传递参数到生成器,示例中"while True"会使生成器一直运行,若要终止,需要调用close方法

def get_list():
    count = 0
    while True:
        print('---------------分割线----------------')
        print('本次循环开始,count初始值:',count)
        outer = yield count
        print('<-------生成器从外部接受到的数据:',outer)
        count += 1
        print('本次循环结束,count值为:',count,'\n')
gen = get_list()
val = next(gen)
print('------>外部调用next从生成器获取到的值:',val)
print()
val = gen.send(20)
print('------>外部从生成器获取到的值:',val)
gen.close

---------------分割线----------------
本次循环开始,count初始值: 0
------>外部调用next从生成器获取到的值: 0

<-------生成器从外部接受到的数据: 20
本次循环结束,count值为: 1 

---------------分割线----------------
本次循环开始,count初始值: 1
------>外部从生成器获取到的值: 1





<function generator.close>

迭代器

迭代器可以使对象像列表、字典一样进行迭代,列表使用索引计数来实现元素的逐个遍历,迭代器封装后的对象可以调用next方法来逐个遍历,同样也支持for循环
实际上,能用next函数获取的下一个值的对象都是迭代器,生成器其实也是迭代器的实例,在数据获取完毕后继续使用next函数,同样会出发StopIteration异常,创建迭代器的方法并不复杂,使用iter函数可以将列表、字典转为迭代器。

list3 = [1,2,3,4,5,6,7,8,9,10]
itor_list = iter(list3)
print('使用next获取元素:',next(itor_list))
print('使用__next__获取元素:',itor_list.__next__())
for i in itor_list:
    print('获取当前元素:',i)
    
使用next获取元素: 1
使用__next__获取元素: 2
获取当前元素: 3
获取当前元素: 4
获取当前元素: 5
获取当前元素: 6
获取当前元素: 7
获取当前元素: 8
获取当前元素: 9
获取当前元素: 10

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wency(王斯-CUEB)

我不是要饭的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值