【python】生成器generator

生成器generator 在Python中3,这种一边循环一边计算的机制,称为生成器,生成器保存的是算法,能节省大量的空间.生成器只记录当前位置,只有一个next()方法。

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

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

简单生成器:

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

L = [x * x for x in range(10)]
G = (x * x for x in range(10))
print(L)
>>>[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(G)
>>><generator object <genexpr> at 0x0000027BFE39C4F8>

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

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

可以使用next(G),计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。正确的方法是使用for循环,因为generator也是可迭代对象. 

带yield 语句的生成器

下面代码可以从第一个元素开始,通过相应的算法推算出后续任意的元素,这种逻辑其实非常类似generator。

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
G=fib(6)
print(G)

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。 

加强的生成器

一些加强特性加入到生成器中,所以除了 next()来获得下个生成的值,用户可以将值回送给生成器[send()],在生成器中抛出异常,以及要求生成器退出[close()]。

def gen(x):
    count = x
    while True:
        val = (yield count)
        if val is not None:
            count = val
        else:
            count += 1
G = gen(5)
print (next(G))
>>>5
print (next(G))
>>>6
print (next(G))
>>>7
print('====================')
print (G.send(9))#发送数字9给生成器
>>>9
print (next(G))
>>>10
print (next(G))
>>>11
G.close()

 通过send()可以把数据9发送给生成器,当生成器close后,就不能再对生成器进行操作了。 

原文地址:https://www.cnblogs.com/paulwinflo/p/12259647.html