1.生成器(generator)

通过列表生成式(列表推导式),我们可以直接创建一个列表

但是,受到内存限制,列表容量肯定是有限的,而且创建一个100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间就白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?

这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器。

 

注意:列表推导式和生成器的区别,生成器是用()的,而列表推导式是用[]

两种通知生成器生成元素的方式:

方式1:调用__next__()

 

 1 newlist = [x*3 for x in range(10)]
 2 print(newlist)
 3 print(type(newlist))
 4 
 5 g = (x*3 for x in range(10))
 6 print(g)
 7 print(type(g))
 8 
 9 # 每调用一次,就生成一个元素(通过调用__next__())
10 print(g.__next__())
11 print(g.__next__())
12 print(g.__next__())

 

生成器-next(),__next()__,yield,send(),协程方法_调用函数

 

方式2:使用系统自带的next()调用,系统内置的函数next(生成器对象),每调用一次,next()会产生一个元素

 1 # 每调用一次,就生成一个元素(通过调用__next__())
 2 print("=========使用__next()__方法=========")
 3 print(g.__next__())
 4 print(g.__next__())
 5 print(g.__next__())
 6 
 7 
 8 # 使用系统自带的next()方法
 9 print("================使用next()方法================")
10 print(next(g))
11 print(next(g))

生成器-next(),__next()__,yield,send(),协程方法_生成器_02

 

生成器中使用yield

 1 # 只要在函数中有yield关键字,说明这个函数不是函数了,就变成了生成器了
 2 """
 3 步骤:
 4     1.定义一个函数,函数中使用yield关键字
 5     2.调用函数,接收调用的结果
 6     3.得到的结果就是生成器
 7     4.可以借助于next()或__next()__得到元素
 8 """
 9 
10 def func():
11     n = 0
12     while True:
13         n += 1
14         yield n   # 类似于return n,同时yield也有暂停的功能
15 
16 # 得到一个生成器对象
17 g = func()
18 print(type(g))
19 
20 # 使用next()执行函数里面的内容
21 print(next(g))
22 # 第二次执行next()时候,就在while循环里面执行了,因为yield有暂停功能
23 print(next(g))
24 print(next(g))
25 print(next(g))

生成器-next(),__next()__,yield,send(),协程方法_调用函数_03

 用yield生成斐波那契数列

 1 def fib(length):
 2     a, b = 0, 1
 3     n = 0
 4     while n < length:
 5         yield b
 6         a, b = b, a+b
 7         n += 1
 8 
 9         
10 g = fib(8)
11 print(next(g))
12 # 每次从yield暂停的位置执行
13 print(next(g))
14 print(next(g))
15 print(next(g))
16 print(next(g))

生成器-next(),__next()__,yield,send(),协程方法_斐波那契数列_04

 

在生成器中return ,return后面的信息会出现在异常里面

 1 def fib(length):
 2     a, b = 0, 1
 3     n = 0
 4     while n < length:
 5         yield b
 6         a, b = b, a+b
 7         n += 1
 8 
 9     return '没有更多元素了!'   # return就是在得到StopIteration后的提示信息
10 
11 
12 g = fib(8)
13 print(next(g))
14 # 每次从yield暂停的位置执行
15 print(next(g))
16 print(next(g))
17 print(next(g))
18 print(next(g))
19 print(next(g))
20 print(next(g))
21 print(next(g))
22 print(next(g))

生成器-next(),__next()__,yield,send(),协程方法_调用函数_05

 生成器的send()方法

 1 """
 2 生成器方法:
 3     1.__next()__:获取下一个元素
 4     2.send(value):向每次生成器调用中传值,注意:第一次调用使用send(None)
 5 """
 6 def gen():
 7     i = 0
 8     while i < 5:
 9         temp = yield i  # return i + 暂停
10         print("temp:", temp)
11         i += 1
12     return '没有更多数据了!'
13 
14 
15 g = gen()
16 
17 print(g.send(None))
18 n1 = g.send('呵呵')
19 print("n1:", n1)
20 n2 = g.send('哈哈')
21 print("n2:", n2)

生成器-next(),__next()__,yield,send(),协程方法_python_06

 协程使用yield

 1 # 进程 > 线程 >进程
 2 # 当在一个线程里需要做多个任务的话,就需要引入协程,就是任务之间交替进行(多个任务之间的切换)
 3 
 4 def task1(n):
 5     for i in range(n):
 6         print("正在搬第{}块砖".format(i))
 7         yield None
 8 
 9 
10 def task2(n):
11     for i in range(n):
12         print("正在听第{}首歌".format(i))
13         yield None
14 
15 
16 g1 = task1(5)
17 g2 = task2(5)
18 
19 while True:
20     try:
21         g1.__next__()
22         g2.__next__()
23 
24     except:
25         print("循环结束")
26         break

生成器-next(),__next()__,yield,send(),协程方法_调用函数_07

 

 总结:

定义生成器的方式:

1.通过列表推导式的方式

  g=(x+1 for x in range(6))

2.函数+yield

  def func():

    ...

    yield 

  g = func()  # 此时g就是生成器

3.产生元素

  (1)next(generator),每调用一次,就会产生一个新的元素,如果元素产生完毕,再次调用的话,就会产生异常,StopIteration

  (2)生成器自己的方法:g.__next()__,g.send(value)

4.生成器的应用

  协程