python生成器与表达式

  1. 生成器函数:使用常规的def语句进行编写,但是使用yield语句一次返回一个结果,在每次结果产生之间挂起和恢复他们的状态。
  2. 生成器表达式:类似列表推导,但是,它们返回按需产生结果的一个对象,而不是创建一个结果列表。
    def gensquares(N):
        for i in range(N):
            yield i**2
    
    for i in gensquares(5):
        print(i,end=':')  #0:1:4:9:16:
    
    x=gensquares(r)
    next(x)  #0
    next(x)  #1
    next(x)  #4

    返回的生成器对象有一个__next__方法。

  3. 生成器对大型程序而言,在内存使用和性能方面都更好。它们允许函数避免预先做好所有的工作,在结果的列表很大或者在处理每一个结果都需要很多时间时,生成器将产生一系列值的时间分散到每一次的循环迭代中去。
  4. 生成器的send方法生成一系列结果的下一个元素,值可以通过调用G.send(value)发送给一个生成器G。之后恢复生成器代码的执行,并且生成器中的yield表达式返回了发送给send函数的值。如果提前调用了正常的G.__next__方法,yield则返回None。
    def gen():
        for i in range(10):
            x=yield i
            print(x)
    
    G=gen()
    next(G)  #0
    G.send(77)  #77  1
    G.send(88)  #88   2
    next(G)    #None  3
  5. 生成器表达式就像一般的列表推导一样,而且也支持所有列表推导的语法(包括if过滤器和循环嵌套),但它们是包括在圆括号中而不是方括号里的(跟元组一样,它们的圆括号通常是可选的)。
  6. 生成器表达式不是在内存中构建结果,而是返回一个生成器对象——一个自动被创建的可迭代对象。这个可迭代对象会支持迭代协议,并在任意的迭代语境中产生一个结果列表。可迭代对象在激活时也持有生成器的状态。可以出现在任何的迭代上下文中。如果生产期表达式包在其它的括号之内,比如在函数调用之中,生成器自身的括号就不是必须的。生成器表达式也是一种对内存空间的优化,他们将生成结果拆分成更小的时间片:他们会一部分一部分产生结果,而不是让调用者再一次调用中等待整个集合中被创建出来。
    G=(x**2 for x in range(4))
    iter(G) is G  #True
    next(G)  #0
    next(G)  #1
    
    for num in (x**2 for x in range(4)):
        print('%s,%s'%(num,num/2.0)
    #0,0.0
    #1,0.5
    #4,2.0
    #9,4.5
    
    sum(x**2 for x in range(4))  #14,不需要括号
  7. 生成器函数和表达式自身都是迭代器,因此只支持一次活跃迭代,一旦任意迭代器运行结束,所有迭代器都将用尽——我们必须产生一个新的生成器一边重新开始。
  8. yield form扩展:
    def both(N):
        yield from range(N)
        yield from (x**2 for x in range(N))
    
    list(both(5))
    #[0,1,2,3,4,0,1,4,9,16]

猜你喜欢

转载自www.cnblogs.com/biwangwang/p/11331807.html
今日推荐