Python生成器浅谈

首先,生成器generator是一个对象,而且是可迭代的,它保存的是算法,只有在用的时候调用它它才会去计算,这样就节省了大量的空间。

创建generator有很多方法,比较简单的一种就是把列表生成式的[]换成(),即可生成一个生成器。

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

可以看到g此时已经变为生成器对象,不会直接返回结果,需要调用时才会去返回,一次一次的调用可以使用next()

>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)

>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):
  File "<pyshell#21>", line 1, in <module>
    next(g)
StopIteration

当所有值都取完后,就会报错StopIteration,抛出异常,可见生成器在没有元素可取时就会报错,只能用的时候才去调用。

当然这是笨方法,因为生成器是可迭代的对象,所以正确的打开方式应该是for循环

>>> a = (x * x for x in range(5))
>>> for i in a:
    print(i)

    
0
1
4
9
16

>>> for i in a:
    print(i)

    
>>> 

再次去执行for循环,没有打印出结果,因为此时已经没有更多的元素可以打印,但是不会抛出异常,所以使用for循环不用考虑异常的问题。

另外,生成器还可以由函数改成,在需要返回数据的地方加上yield即可,如下,把斐波那契函数改成生成器。

 

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a , b = b, a + b
        n += 1
    return 'done'

此时,fib()函数就需要循环调用才会显示每次的结果

g = fib(9),做完赋值操作,此时不会像函数一样调用就会马上去执行函数体,而且需要去调用g一次才会去执行一次

可以使用next(g)去调用,也可以使用for循环,但是因为return里的内容保存在StopIteration的value中,但是for循环不会抛出异常,所以使用for循环拿不到return的返回值,需要打印异常里的value值才会拿到return的返回值。

for i in g:
    print(i)

1
1
2
3
5
8
13
21
34

拿到return返回值的方法,需要使用next一次次调用,抛出异常后捕获到再打印出来:

while True:
    try:
        x = next(g)
        print(x)
    except StopIteration as e:
        print("generator return value:", e.value)
        break

运行结果:

1
1
2
3
5
8
13
21
34
generator return value: done

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值