Python函数(十一)-生成器
首先看一下什么是列表生成式
>>> [i*2 for i in range(10)] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] >>> a=[] >>> for i in range(10): ... a.append(i*2) ... >>> a [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
这一句代码就实现了三句代码的效果,这一句代码就是列表生成式
列表如果存的数据太多,就会占用很大的存储空间
如果只取列表中的一些数据,那么其它不用的数据占用的存储空间就白占了
生成器也能存储数据,但是它只记录当前数据,剩下的数据都还没生成,这样就不会占用太多的存储空间
怎么创建一个生成器呢?
>>> [i*2 for i in range(10)] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] >>> (i*2 for i in range(10)) <generator object <genexpr> at 0x0000021C9C2E5258>
这样就是一个生成器了,没有直接生成数据
要取一个数据就生成一个数据
那么怎么获取生成器里的数据呢?
>>> b = (i*2 for i in range(10)) >>> b <generator object <genexpr> at 0x0000021C9C2E5308> >>> b.__next__() 0 >>> b.__next__() 2 >>> b.__next__() 4 >>> next(b) 6 >>> next(b) 8 >>> next(b) 10
生成器使用next()方法获取数据,next(b),这是Python3和Python2通用的方法
Python3中还可以用__next__()方法,b.__next__()
Python2中用next()方法,b.next()
但是用next()方法一次次取数据太麻烦,所以通常都用for循环来打印数据
>>> c = (i*2 for i in range(10)) >>> for n in c: ... print(n) ... 0 2 4 6 8 10 12 14 16 18
如果函数里有yield关键字,这个函数就是生成器
# -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" def test(n): m = 0 b = 0 while m<n: print("before yield") yield b b = b+3 print("after yield") m =m+1 return "test return" a =test(10) while True: try: b = a.__next__() print("in the next",b) except StopIteration as e: print(e.value) #StopIteration的value为生成器的返回值 exit()
运行结果
运行过程:
首先是调用test()函数
然后执行while循环
到__next__()方法的时候,跳到test()函数
执行完yield后,没继续执行下面的语句,而是返回到__next__()方法后的语句
执行完该语句后继续执行while循环,执行__next__()方法
然后又跳转到yield后的语句
生成器调用next()方法的时候执行,执行到生成器中的yield的时候返回,然后执行next()方法后的语句,再执行到next()方法的时候,就会跳到执行yield的语句,之后执行yield后的语句
用生成器实现单线程多并发
# -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import time def consumer(name): print('%s准备吃包子' %name) while True: baozi = yield print('%s包子来了,被%s吃了' %(baozi,name)) def producer(): c = consumer('张三') c2 = consumer('李四') c.__next__() c2.__next__() print('我开始准备做包子了') for i in range(10): time.sleep(1) print('我做了2个包子') c.send('肉') #调用yield,并传值 c2.send('菜') if __name__ == '__main__': producer()
send方法不仅可以调用yield,还给yield传值
运行结果
实现了单线程多并发的效果