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__())
方式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))
生成器中使用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))
用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))
在生成器中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))
生成器的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)
协程使用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
总结:
定义生成器的方式:
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.生成器的应用
协程