Python从放弃到入门——生成器generator

生成器表达式

上一节我们讲到了列表生成式、字典生成式、集合生成式、那有没有元组生成式呢?我们用其他生成式的方式将其包在()中构造一个试试看。

t=(i*i for i in range(1,6))
print(t)
<generator object <genexpr> at 0x00000000020D7E58>

我们得到是一个叫做生成器(generator)的对象。因为元组是不可变类型的对象,无法在代码中动态地创建元组对象。
那么如何生成器的元素呢?方法有两种
1.调用内置函数next,直到抛出StopIteration时表示没有更多的元素了。
2.使用for-in循环遍历,从而不需要关心StopIteration的错误。

>>>t=(i*i for i in range(1,6))
>>>print(next(t))
1
>>>print(next(t))
4
>>>print(next(t))
9
>>>print(next(t))
16
>>>print(next(t))
25
>>>print(next(t))
StopIteration

>>>t=(i*i for i in range(1,6))
>>>for item in t:
...    print(item)
1
4
9
16
25

生成器是惰性推算的,其中保存的是推算所有的算法。当使用next()或for-in循环时,才推算出需要的元素。受到内存限制,如列表生成式的容量肯定是有限的。当元素较多时,使用生成器能大量地节省内存。

生成器函数

除了上述的生成器表达式外,算法比较复杂时还可以使用生成器函数。生成器函数使用关键字yield返回推算的元素。
让我们来看一个斐波那契数列的例子

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

运行以上代码得到的输出如下,我们得到了斐波那契数列的前6个元素。

1
1
2
3
5
8

有没有方法能保留所有的斐波那契数列,需要时传入所需个数的参数就能推算出指定的元素。
只需对上述的代码稍作改动即可。

def fib(n):
    i=0
    a,b=1,1
    while i<n:
        yield a #将此处改为yield
        a,b=b,a+b
        i+=1
fib(6)

此时调用fib(6)不会返回任何值,generator函数的“调用”实际返回一个generator对象。
我们同样可以用next()或for-in循环来获取元素。

>>>print(fib(6))
>>>ge=fib(6)
>>>print(next(ge))
>>>print(next(ge))
>>>print(next(ge))
>>>print(next(ge))
>>>print(next(ge))
>>>print(next(ge))
<generator object fib at 0x0000000001E47F48>
1
1
2
3
5
8

如果此时我们继续上面的代码对用for-in循环将得不到任何输出。

for item in ge:
    print(item)

因为生成器只支持一次迭代。因此需要重新获取生成器。

ge=fib(6)
for item in ge:
    print(item)
1
1
2
3
5
8

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值