Python学习笔记之生成器

上一章我们介绍了列表生成式。通过列表生成式,我们可以直接创建一个可以按照某种算法求得的 list。在两种情况下,列表生成式会显得不是很合理。
第一,当 list 占用内存很大时。如果一个 list 种有几百万的元素,那么该列表会占用很大空间,这时如果直接用列表生成式生成,那么显得不太合适。
第二,当 list 元素很多,但大多数情况下只访问前面几个元素时。这时如果使用列表生成式,不仅浪费内存空间,生成过程也浪费时间。
综上,列表生成式就会显得无力。既然我们的列表可以按照某种算法求得,那么我们是否可以只把算法保存下来,之后在需要的时候通过循环推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
创建一个generator,有两个重要的方法。下面分开介绍:

  1. 把列表生成器中的 [] 改为 (),代码如下:
    # 列表生成器
    L = [x * x for x in range(5)]
    
    # 结果如下
    # [0, 1, 4, 9, 16]
    
    
    # 生成器
    g = (x * x for x in range(5))
    print(g)
    
    # 结果如下,表明 g 是一个generator
    # <generator object <genexpr> at 0x0000025D8B40A258>
    
    generator有两种迭代方法,一种是调用方法 next(generator g);另一种是 for 循环,因为generator也是可迭代对象。
    (1) 迭代方法一: next(generator g)
    # 调用方法 next(g) 迭代生成器
    g = (x * x for x in range(5))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    
    # 结果如下
    # 0 1 4 9 16
    # Traceback (most recent call last):
    #     File "D:Python/Python基础/test.py", line 12, in <module>
    #         print(next(g))
    # StopIteration
    
    该方法的缺点显而易见。我们不知道一个生成器中元素的个数,只能尝试性的调用 next() 试探,当抛出 StopIteration 的错误时,结束迭代。
    (2) 迭代方法二:for循环
    # for循环迭代一个生成器
    g = (x * x for x in range(5))
    for x in g:
        print x
    
    # 结果如下
    # 0 1 4 9 16
    
  2. 如果一个函数定义中包含 yield 关键字,那么这个函数就不再是一个普通函数,而是generator。
    # 定义一个求裴波那契数列的生成器
    # max 表示最大数列下标,n 表示目前计算到的位置,a 和 b 均用与计算
    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b
            a, b = b, a + b
            n = n + 1
        return 'done'
    
    这里需要介绍一下关键字 yield。生成器和函数的不同在于执行流程不同:函数是顺序执行,当遇到return时返回;而生成器则不同,生成器再每次调用 next(generator g) 时被执行,当遇到 yield 时返回后面的值并停止,再次调用next(generator g) 从上次返回的yield语句处继续执行。
    # 函数式生成器使用
    for x in fib(6):
        print(x)
    
    # 结果如下
    # 1 1 2 3 5 8
    
    如果需要return后面的返回值,方法如下:
    # 获取 return 后面的值的方法
    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
    # Generator return value: done
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值