python 生成器

什么是生成器(generator)?

一边循环一边计算的机制,称为生成器。
计算实际上是按照某种规则在计算,这就要求生成器内元素是按照某种算法推算出来的。在计算的过程中,不是一次计算全部,而是根据规则,计算一次,输出,再计算一次,输出…

为什么要有生成器(generator)?

比如你想要一次生成大量数据,但是内存是有限的,而且可能大量数据中你只需要访问前面部分元素,所以后面的元素是白白的占用了内存。
简单来说,你需要可以生成大量元素,但是又不想要占用太多内存就可以用生成器(generator)

生成器的创建
1.一种简单的创建方式:

先看一个简单的列表生成式:
在这里插入图片描述
使用列表生成式创建了一个简单的列表,赋值给L,同时可以直接输出L中的全部内容。
第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
在这里插入图片描述
这样就创建了一个生成器,但是我们发现,并不能直接像列表那样输出里面的全部内容,那想要查看生成器的内容怎么办?
使用next()函数或者使用for...in...迭代:

使用next()函数

next()函数将生成器内的元素一个一个的输出:
在这里插入图片描述
实际上,生成器generator中保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
可以看出来,每一次计算,之前的输出就输出了,没办法回到上一步状态。

使用for循环输出:

生成器generator是可迭代对象(Iterable)
在这里插入图片描述
我们创建一个生成器对象,使用for循环输出,而且我们发现输出都最后的时候,并没有像使用next(g)那样报错。所以使用for循环来迭代它,并不需要关心StopIteration的错误。

2.创建比较复杂的生成器

如果我想要创建更加复杂点的生成器对象呢,不是上面那种一两句代码就可以写出来的,这时候就要利用函数来实现了。
先看一个简单的函数:实现斐波那契数列的函数

#斐波那契数列 1,1,2,3,5,8,13,....
#输出前 n 项的数据
def fib(n):
    #添加最前面两项,生成会很方便
    a,b = 1,0
    for i in range(n):#前n项循环n次
        #下面是它的生成规则
        sum = a+b
        a,b = b,sum#
        print('%d '%sum,end='')
#直接调用就可以输出结果
fib(8)

在这里插入图片描述
现在我们需要的是一个生成器generator,首先要把这个函数变成生成器函数,只需要一点简单的改动,print('%d '%sum,end='')[这么写只是为了好看]改成yield (sum),

#斐波那契数列 1,1,2,3,5,8,13,....
#输出前 n 项的数据
def fib2(n):
    #添加最前面两项,生成会很方便
    a,b = 1,0
    for i in range(n):#前n项循环n次
        #下面是它的生成规则
        sum = a+b
        a,b = b,sum
        yield (sum)

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

对于之前的fib(8)我们直接调用就直接输出了结果,但是现在使用fib2(8)只是生成一个generator对象,不会产生所有的结果:
在这里插入图片描述
我们可以使用next()或者for循环输出结果:
在这里插入图片描述

理解:

generator函数和普通函数的执行流程不一样。普通函数是顺序执行,里面有循环就把循环执行完,只有在遇到return语句或者最后一行函数语句才返回。
而变成generator的函数,在每次调用next()的时候执行,遇到yield语句,输出yield处的内容,接着函数返回。再次执行时从上次返回的yield语句处的下一句 要执行的代码处 继续执行。

关于yield的解释:python中yield的用法详解——最简单,最清晰的解释

举个简单的列子解释yield语句:

def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)
    #含有yield语句,就是一个generator函数,不是普通函数

使用generator函数创建一个generator对象

o = odd()
o
#由于odd()是一个generator函数,这时候并不会执行函数内容,
#只有在是使用next(o)时,函数才开始执行

在这里插入图片描述

next(o)
#调用next()函数,开始执行函数,首先执行print('step 1'),输出step 1
#接着遇到yield 1语句,输出1,函数返回

在这里插入图片描述

next(o)
#再次调用next(o),程序从上一次停止的地方执行,上次的下一步要执行print('step 2')
#所以现在执行print('step 2'),输出step 2
#接着遇到yield 3 语句,输出3,函数返回

在这里插入图片描述

next(o)
#和上面一样,从上次停止的地方的开始执行, print('step 3'),输出step 3
#接着遇到yield 5 语句,输出5,函数返回

在这里插入图片描述
在这里插入图片描述
还需要注意的是:
上面的odd()是一个generator函数,每次调用odd()生成的都是一个新的generator对象,如果你每次都是next(odd()),则结果始终是一样的:
在这里插入图片描述
正确的写法是创建一个generator对象,然后不断对这一个generator对象调用next(),或者使用for迭代。
在这里插入图片描述

参考:生成器

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值