什么是生成器:
通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器:generator。
生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。
生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是,不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器。
创建列表,直接在内存生成,不管调不调用,都占用内存空间。而创建生成器,只有调用时,才会在内存生成。
列表和生成器的区别在于最外层,最外层为[]时为列表,最外层为()时为生成器generator
列表如下>>>[i*2 for i in range(10)][0, 2, 4, 6, 8, 10, 12, 14, 16, 18]生成器generator如下>>>(i*2 for i in range(10))<generator object <genexpr> at 0x02E9D2A0>
生成器不能支持如同列表调用数据的方式,如列表的切片,如果想要调用,方式有通过for循环,一个一个去调用,调用那次就产生那次数据。
生成器只记住当前位置,通过__next__()方法获取下一个位置的值,不能往后退,不能跳,只能一个一个去取。
生成器虽然非常强大,但是如果算法的推算非常复杂,用列表生成式的for循环无法生成的时候,可以用函数的方式实现。
例如斐波那契数用列表生成式是写不出来的,但是用函数写就简单很多了。
斐波那契数:当前数值等于前面两个数值相加。
def fib(max):
n,a,b=0,0,1
while n <max:
yeild b
a,b=b,a+b
n+=1f=fib(100)print(f.__next__())#通过调用next方法,调用一次就生成一次数据
生成器除了可以节省内存外,还可通过yield实现在单线程情况下实现并发运算
1 # Author : 梁观康
2
3
4 # 顾客和营业者的关系
5
6 import time
7
8 def Consumer(name):#顾客函数
9 print('%s has started to eat the steamed stuffed bun!'%name)
10 while True:
11 class = yield
12 print('The %s is coming,but eaten by %s!'%(class,name))
13
14 def Producer(name):#营业者函数
15 C1 = Consumer('Luna')#生成对象
16 C2 = Consumer('Iriving')#生成对象
17 C1.__next__()#调用对象
18 C2.__next__()#调用对象
19 print('LGK is starting to make the steamed stuff bun!!')
20 for i in range(10):#循环10次
21 time.sleep(1)#休眠1秒
22 kind = ['肉包','菜包']
23 print('LGK has made two buns, the first one is %s,the second one is %s'%('肉包','菜包'))
24 C1.send(kind[0])#给yield赋值
25 C2.send(kind[1])#给yield赋值
26
27
28 Producer('LGK')