美文网首页
python 中的生成器

python 中的生成器

作者: yeathMe | 来源:发表于2018-01-05 15:01 被阅读0次

    1为什么要用生成器
    a=[x2 for x in rang(10)] 表示使用rang(10) 中的数生成一个列表,列表中的 每一个元素都是 x2,
    这样a的结果就是 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

    但是如果我们 使用a=[x*2 for x in rang(110000)] 这里的range范围比较大,那么a重元素的数量就会非常多,占用很大的内存空间。

    我们有这样一种需求: 每次从a中取出一个元素,但是什么时候取是不知道的,所以我们希望等到取元素的时候再计算a中的下一个元素,也就是我们保存生成a 列表的 算法范式 (x*2),这样a就会占用很小的内存空间。这就是生成器 要解决的问题。

    b=(x*2 for x in range(100))
    print next(b)
    print next(b)
    print next(b)
    输出:
    0
    2
    4
    
    上面(x*2 for x in range(100)) 就是一个生成器,将这个生成器赋值给b引用,通过next方法可以获取生成器中的 下一个元素
    

    2创建生成器

    1,创建生成器的第一种方式,将列表的[] 改为(), a=(x2 for x in range(10)).
    注意区别 a=[x
    2 for x in range(10)] 这个中括号称为列表推导式, 其特点是立即生成列表中的元素。
    而上面的a=(x*2 for x in range(10)). 这里返回的a是一个生成器。

    1. 带有yield的方法 被调用后会返回一个生成器对象。
    def createNum():
        print "createNum start"
        i=0
        a=1
        b=1
        while i<5:
            a,b=b,a+b
            print a,b
            i=i+1
            yield b
        print "createNum stop"
    
    generator=createNum()
    print generator #<generator object createNum at 0x0000000003133900>
    print next(generator)
    print next(generator)
    
    
    

    这里有一个问题, 调用含有yield方法 返回一个生成器对象,然后我们可以使用next(generator)获取下一个值,这里的这个值是哪个变量的值,是如何生成的? 这取决于yield 语句中 包含的 表达式的值。
    当我们调用next(generator) 的时候,生成器会自动运行到yield语句的位置,并返回yield语句中表达式的值 。
    这里包含了这两个操作。

    另一个问题,上面显示 while循环将会循环5次,5次之后就退出了while,也就是说next(generator )最多调用五次,如果调用了六次,那么第六次执行next(generator)的时候将会出现错误stopIteration

    3从生成器中获取元素

    1,next(generator)
    2,generator.next()
    3 使用for循环遍历生成器对象
    for x in generator

    4 send 和next

    def testSend():
        i=0
        while i<5:
            temp=yield  i
            print (temp)
            i=+1
    
    generatorSend=testSend()
    print next(generatorSend)
    print(next(generatorSend))
    
    输出结果:
    0
    None
    1
    

    当第一次运行next的时候,程序会执行到testSend方法的yield语句的地方,然后程序被挂起,此时返回i的值是0,因此next方法的返回值是0.
    当第二次运行next的时候 会首先置信print(temp),然后挂起在yield语句的地方,并输出print(next(generatorSend))
    但是为什么 print(temp)会输出 none?? 按照我的理解temp的值为第一次执行yield i的返回值,也就是i=temp=0。
    书中给出的解释如下:


    image.png

    这里有一个问题, temp=yield i 和 yield i的区别,前者是yield表达式,后者是yield语句;表达式总是有值的,而语句不一定有值。
    在本示例中yield是作为一个表达式使用的,这个表达式的值是yield方法返回的一个值,而这个值是通过外部send方法发送的值,所以temp的值就是send方法发送的值。

    简单来说 next得到的值是yield 后面他的表达式 计算得到的值。
    yield i 整体的值是send方法发送的值,temp表示将yield i整体的值赋值给temp,而不是将yield语句中内部子表达式的值赋给temp。

    5 send 方法

    
    def testSend():
        i=0
        while i<5:
            temp=yield  i
            print (temp)
            i=i+1
    
    generatorSend=testSend()
    print next(generatorSend)
    print generatorSend.send("xx")
    print(next(generatorSend)))
    输出结果:
    0
    xx
    None
    2
    
    

    从这个例子中我们可以看出send方法 有两个作用
    (1)将send方法的参数作为 yield i 表达式的整体结果赋值给temp
    (2)可以使得程序继续从yield挂起的地方继续往下运行,直至再次遇到yield挂起,在这一点上和next方法相同
    另外补充两点
    (3) send方法之前之前,程序挂起在yield语句的地方,send 方法的参数作为本次yield i整体的结果。也就说send方法只表示本次yield i整体的结果,而不影响后续 执行yield i 整体的结果。这也要求 send之前需要 先将程序挂起在yield处

    (4)send(None)与next ()两个函数作用相同。

    相关文章

      网友评论

          本文标题:python 中的生成器

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