生成器

作者: 戈羽殇雪 | 来源:发表于2019-11-06 18:24 被阅读0次

    列表生成式,一般的我们想把对一个列表的函数进行操作,一般是用循环进行调用。
    例如我们想将0-9的元素乘以2,一般来讲:

    for i in range(10):
        print(i*2)
    

    而我们使用列表生成式的话,直接可以写作

    list=[ i*2 for i in range(10)]
    

    直接打印即可,得到一个列表,这样简洁了很多,同时不需要循环引入
    列表生成式,在面对大数据量的时候,不会直接占用那么大的内存,它
    只是引入了一个算法,只有在调用到列表的这个元素时,它才会生成这个元素,若一个100w元素的列表,传统的调用方式,会首先分配部分内存给这100w个元素,但若使用列表生成式,只有开始调用时,才会占用内存空间。

    而生成器简单来讲,就是将列表生成式外卖呢的[]转换成()

    list=(i*2 for i in range(10)]
    print(type(list))
    output:
    <class 'generator'>
    

    生成器只有一种方法,就是next方法,调用方式为:

    f=(i*i for i in range(5) )
    print(f.__next__())
    print(f.__next__())
    

    生成器只能记录当前的位置,不计前后,没有上一个这种方法
    如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现
    实现斐波那契数列

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

    这里需要注意的一点,最关键一点为a,b=b,a+b,
    如果顺序执行的方式去执行

    a=b
    b=a+b
    

    则循环输出结果为:1,2,3,6.....违背了数列的规律
    实际上应该理解为:

    t=(b,a+b)
    a=t[0]
    b=t[1]
    

    输出为:1,1,2,3,5,8
    而我们这里可以引入生成器,只需将print(b)修改为yield 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'
    

    同时调用时可以查看fib(6)的类型,可以看到为
    <class 'generator'>
    若要调用生成器还是需要使用next方法
    print(f.next())
    将6个值都取到则需要调用6次next方法
    但当调用第7次时,程序会报错,抛出“StopIteration”的异常
    因此我们可以改写调用函数:

    def fib(max):
        n,a,b =0,0,1
        while n < max:
            yield b
            a,b = b,a+b
            n = n+1
        return 'done'
    f=fib(10)
    while True:
        try:
            x = next(f)
            print('f:',x)
        except StopIteration as e:
            print('Generator return value:',e.value)
            break
    

    while 循环中的next函数实际作用与内置函数f.next()一致
    通过异常判断来修正程序,不会出现报错的情况,同时中断程序

    另外我们可以使用生成器来写一个简单的生产者消费者模型

    def consumer(name):
        print("%s 准备吃包子了!" %name)
        while True:
            baozi=yield
            print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
    c=consumer('carl')
    c.__next__()
    c.send("韭菜馅")
    

    我们看到这里将生成器赋值给“baozi”,这里的生成器就是保存状态,next是唤醒这个生成器,而用send方法是给生成器传值,而consumer是消费者,吃包子的

    next方法与send方法都可以调用生成器,但不同的是next方法是调用生成器的值,而send方法则是向生成器传值
    而consumer是吃包子的,send值则代表生产包子

    完整的做包子,吃包子模型:

    import time
    
    def consumer(name):
        print("%s 准备吃包子啦!" % name)
        while True:
            baozi = yield  ##将生成器赋值给包子
            print("包子[%s]来了,被[%s]吃了!" % (baozi, name))
    c=consumer('cris')
    
    def producer(name):
        c = consumer('A')
        c2 = consumer('B')
        c.__next__()
        c2.__next__()
        print("%s开始准备做包子啦!" %name)
        for i in range(1,10):
            time.sleep(1)
            print("做了%s个包子!" %i)
            c.send(i)
            c2.send(i)
    producer("cris")
    

    相关文章

      网友评论

          本文标题:生成器

          本文链接:https://www.haomeiwen.com/subject/ypwdbctx.html