Python小程序练习三之生成器小例子

为什么要使用生成器

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。比如创建一个100万个元素的列表,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

什么是生成器

    所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

创建生成器

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

1 # The author is tou
2 # Version:Python 3.6.55
3 print([i*2 for i in range(10)]) #列表生成式
4 
5 b = (i*2 for i in range(10))    #生成器
6 # print(b.__next__())
7 # print(b.__next__())           #__next__()方法取下一个值
8 for i in b:                     #亦可迭代取值
9     print(i)
创建生成器

    创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。

 

    我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

    如果要一个一个打印出来,可以通过__next__()方法获得generator的下一个返回值

    generator保存的是算法,每次调用__next__(),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

    当然,上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象。

实现斐波拉契数列(Fibonacci):

    除第一个和第二个数外,任意一个数都可由前两个数相加得到。

 1 def fib3(max):                                     #加入生成器的斐波那契数列,并抓取超过次数所报错误,并返回return值
 2     n,a,b = 0,0,1
 3     while n<max:
 4         yield b
 5         a,b = b,a+b
 6         n = n+1
 7     return "done"
 8 #print(fib(10))                                    #直接打印
 9 f = fib3(10)
10 while True:
11     try:
12         print("f.__next__():",f.__next__())
13     except StopIteration as e:                     #抓取超过次数所报错误
14         print("Generator return value :",e.value)
15         break
斐波那契数列

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。

 1 # The author is tou
 2 # Version:Python 3.6.5
 3 import time
 4 
 5 def consumer(name):                                     #消费者
 6     print("%s准备吃包子啦!"%name)
 7     while True:
 8         baozi = yield
 9         print("第[%s]份包子来了,被[%s]吃了!"%(baozi,name))
10 # c = consumer("tou")
11 # c.__next__()
12 # b1 = "韭菜馅"
13 # c.send(b1)   #给yield赋值
14 
15 def producer(name):                                     #生产者
16     c = consumer("toutou")
17     c.__next__()
18     print("%s开始准备做包子了!"%name)
19     for i in range(10):
20         time.sleep(1)
21         print("%s做了两个包子!"%name)
22         c.send(i+1)
23 producer("zhuozhuo")
通过yield实现在单线程的情况下实现并发运算的效果

 

posted @ 2018-04-12 22:54  偷偷tou  阅读(581)  评论(0编辑  收藏  举报