zoukankan      html  css  js  c++  java
  • 9、【转载】Python生成器generator之next和send运行流程

    def consumer():
        r = 'here'
        for i in range(3):
            yield r
            r = '200 OK' + str(i)
    
    c = consumer()
    n1 = next(c)
    n2 = next(c)
    n3 = next(c)

    对于普通的生成器,第一个next调用,相当于启动生成器,会从生成器的第一行代码开始执行,直到第一次执行完yield语句后,中断,将r值返回并暂时跳出生成器函数。

    然后第二个next调用,进入生成器函数后,从yield语句的下一句语句开始执行,然后重新运行到yield语句,执行后,跳出生成器函数,

    后面再次调用next,依次类推。

    了解了next()如何让包含yield的函数执行后,我们再来看另外一个非常重要的函数send(msg)。

    其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做c.next() 和 c.send(None) 作用是一样的

    需要提醒的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有Python yield语句来接收这个值。

    如果在编辑器中将send(None)注释掉,直接发送一个非None的值,则回报错:

    Traceback (most recent call last):
      File "D:/PycharmProjects/hello/test.py", line 23, in <module>
        produce(c)
      File "D:/PycharmProjects/hello/test.py", line 18, in produce
        r1 = c.send(n)
    TypeError: can't send non-None value to a just-started generator

    个人理解:调用send(非None值)传入参数,就要有相对应的yield语句接受参数!第一次调用先调用send(None),与next()作用一样,均是在generator中将程序执行定位到yield语句,为了下次传入非None值时接收。这可能时python的一种机制吧。

    下面来着重说明下send执行的顺序:

    # -*- coding: utf-8 -*-
    
    def consumer():
        r = ''
        while True:
            n1 = yield r
            if not n1:
                return
            print('[CONSUMER] Consuming %s...' % n1)
            r = '200 OK'
    
    def produce(c):
        c.send(None)
        n = 0
        while n < 5:
            n = n + 1
            print('[PRODUCER] Producing %s...' % n)
            r1 = c.send(n)
            print('[PRODUCER] Consumer return: %s' % r1)
        c.close()
    
    c = consumer()
    produce(c)

    当第一次执行c.send(None)时,启动生成器,从生成器函数的第一行代码开始执行,直到第一次执行到 n1 = yield r 后,跳出生成器函数。这个过程中,n1一直没有定义,如图所示:

    下面运行到 r1 = c.send(1) 时,进入生成器函数,注意这里与调用next的不同。

     这里是从 n1 = yield r 开始执行,把1赋值给n1,但是并不执行yield部分

    下面继续从yield的下一语句继续执行,然后重新运行到yield语句,执行 yield r 后,跳出生成器函数!

    即send和next相比,只是开始多了一次赋值的动作,其他运行流程是相同的。

    运行结果:

    [PRODUCER] Producing 1...
    [CONSUMER] Consuming 1...
    [PRODUCER] Consumer return: 200 OK1
    [PRODUCER] Producing 2...
    [CONSUMER] Consuming 2...
    [PRODUCER] Consumer return: 200 OK2
    [PRODUCER] Producing 3...
    [CONSUMER] Consuming 3...
    [PRODUCER] Consumer return: 200 OK3
    [PRODUCER] Producing 4...
    [CONSUMER] Consuming 4...
    [PRODUCER] Consumer return: 200 OK4
    [PRODUCER] Producing 5...
    [CONSUMER] Consuming 5...
    [PRODUCER] Consumer return: 200 OK5

    备注:转载自http://blog.csdn.net/pfm685757/article/details/49924099,并添加个人的见解

  • 相关阅读:
    [Angularjs]视图和路由(一)
    [Angularjs]ng-show和ng-hide
    解决UNIGUI字体太小的问题
    [FireDAC][Phys][MySQL] MySQL server has gone away
    unidbgrid列排序
    在盒子(2CCC)的日子
    咏南MORMOT中间件免费开源
    unidbgrid单元格操作
    国内安卓软件的恶劣环境
    DELPHI纤程的演示
  • 原文地址:https://www.cnblogs.com/zwb8848happy/p/8576214.html
Copyright © 2011-2022 走看看