WELCOME

不积跬步,无以至千里;不积小流,无以成江海。

Python生成器

1.生成器

  通过列表生成式(列表推导式),|我们可以直接创建一个列表。但是,受到内存限制,列表容量中定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们
仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就
不必创建完整的list,从而节省大量的空间在Python中,这种一边循环一边计算的机制,称为生成器: generator

 

2.通过列表推导式得到生成器

 1 newlist = [x * 3 for x in range(10)]
 2 print(newlist)
 3 
 4 # 得到生成器
 5 g = (x * 3 for x in range(10))
 6 print(type(g))  # >> <class 'generator'>
 7 print(g)  # >> <generator object <genexpr> at 0x000001FA1AF01548>
 8 # 方式一:通过调用__next__()方式得到元素
 9 print(g.__next__())  # >> 0
10 print(g.__next__())  # >> 3
11 print(g.__next__())  # >> 6
12 print(g.__next__())  # >> 9
13 
14 # 方式二:next() 系统内置的函数:next(生成器对象) 每调用一次则会产生一个元素
15 print(next(g))  # >> 12
16 print(next(g))  # >> 15
17 print(next(g))  # >> 12
18 print(next(g))  # >> 15
19 # StopIteration 生成器本来可以产生10个,得到了10个,再调用next(g),则会抛出异常!

 

  通过循环来调用生成器,并加上产生异常的处理:

 

1 g = (x * 3 for x in range(10))
2 while True:
3     try:
4         e = next(g)
5         print(e)
6     except:
7         print('元素产生完毕,没有更多的元素了')
8         break

 

3.借助函数得到生成器

步骤:
    1.定义一个函数,函数中使用yield关键字
    2.调用函数,接收调用的结构
    3.得到的结果就是一个生成器:<generator object func at 0x0000021AEB0B13C8>
    4.借助于next(),__next__()得到元素部分
简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,
Python 解释器会将其视为一个generator,

 

 1 # 函数中出现yield关键字,说明函数就不是一个函数,变成了一个生成器
 2 def func():
 3     n = 0
 4     while True:
 5         n += 1
 6         yield n  # --> (return + 暂停)的作用
 7 
 8 
 9 g = func()
10 print(g)  # >> <generator object func at 0x0000021AEB0B13C8>
11 print(next(g))  # >> 1
12 print(g.__next__())  # >>2
13 
14 '''
15 yield相当于return+暂定的作用,当n=n+1=1时。返回1,然后暂停在这儿,打印1之后,继续从yield下面开始执行
16 '''

 

·  斐波那契数列:

 1 # 斐波那契数列
 2 
 3 def fib(length):
 4     a, b = 0, 1
 5     n = 0
 6     while n < length:
 7         # print(b)
 8         yield b  # return + 暂停
 9         a, b = b, a + b
10         n += 1
11     return '没有更多元素了!!!'  # return就是在得到StopIteration,即错误提示信息
12 
13 
14 g = fib(8)
15 print(next(g))  # >> 1
16 print(next(g))  # >> 1
17 print(next(g))  # >> 2
18 print(next(g))  # >> 3
19 print(next(g))  # >> 5
20 print(next(g))  # >> 8
21 print(next(g))  # >> 13
22 print(next(g))  # >> 21
23 print(next(g))  # >> StopIteration: 没有更多元素了!!!
首先a,b=0,1,0<8,yield b:return b的值,然后暂定,直接跳到print(next(g))
然后跳到下一个print(next(g)),再到a,b=b,a+b这一步,n +=1,说明产生一个元素,
n=1<8,成立,则yield b,即扔出结果1,再又从a,b=b,a+b开始执行。

 

 

 

 

4.send()函数

生成器方法:
__next__():获取下一个元素
    send(value):向每次生成器调用中传值,第一次调用必须传一个空值send(None)
send()的作用是使xx赋值为发送的值(send的参数),然后让生成器执行到下个yield..

使用send(params)需要区分情况。注意:如果生成器未启动,则必须在使用send()前必须要启动生成器,而启动的方法可以是generator.next()或是generator.send(None)
执行到第一个yield处.之后就可以使用send(params)不断传入值了。如果是已启动,则send(params)的作用就是给xx赋值为发送的值(send的参数),然后让生成器执行到下个yield..

为什么需要send(None),也很好理解,因为 生成器还没有走到第一个yield语句,如果我们发生一个真实的值,这时是没有人去接收它的。一旦生成器启动了,就对象接受(即=号左边
的左值xx接受了),之后就可以使用send(params)不断传入值了

 

 1 def gen():
 2     i = 0
 3     while i < 5:
 4         temp = yield i  # return 0 ,暂停
 5         print('temp:', temp)
 6         for x in range(temp):
 7             print('----------->',x)
 8         print('***************')
 9         i += 1
10     return '没有更多数据了'
11 
12 
13 g = gen()
14 # print(next(g))
15 # print(next(g))
16 # print(next(g))
17 
18 print(g.send(None))
19 n1 = g.send(3)
20 print('n1:', n1)
21 n2 = g.send(5)
22 print('n2:', n2)

0
temp: 3
-----------> 0
-----------> 1
-----------> 2
***************
n1: 1
temp: 5
-----------> 0
-----------> 1
-----------> 2
-----------> 3
-----------> 4
***************
n2: 2

 

5.生成器应用(协程)

 1 def task1(n):
 2     for i in range(n):
 3         print('正在搬第{}块砖'.format(i))
 4         yield None
 5 
 6 
 7 def task2(n):
 8     for i in range(n):
 9         print('正在听第{}首歌'.format(i))
10         yield None
11 
12 
13 g1 = task1(5)
14 g2 = task2(5)
15 
16 while True:
17     try:
18         next(g1)
19         next(g2)
20     except:
21         break
22 
23 '''
24 正在搬第0块砖
25 正在听第0首歌
26 正在搬第1块砖
27 正在听第1首歌
28 正在搬第2块砖
29 正在听第2首歌
30 正在搬第3块砖
31 正在听第3首歌
32 正在搬第4块砖
33 正在听第4首歌
34 '''

 

posted @ 2022-03-26 20:27  Ambitious~  阅读(39)  评论(0)    收藏  举报