美文网首页
01-从生成器预激到send,yield交互流程

01-从生成器预激到send,yield交互流程

作者: 依依东望_220b | 来源:发表于2019-01-15 23:07 被阅读0次

def g_01():
    print('---g_01-01---') #代码执行位置标记
    point_01=yield
    print('---g_01-02---')
    for _ in range(5):
        print('---g_01---:{}'.format(point_01))

def main_01():
    g=g_01()
    print('---main_01-01---') #代码执行位置标记
    g.send(None) #我们的核心:预激生成器
    print('---main_01-02---')
    g.send('Android')
'''
执行:
    main_01()
输出结果:
    ---main_01-01---    
    ---g_01-01---                  我们执行完成预先预激生成器后,生成器g_01执行到  ---g_01-01---位置
    ---main_01-02---               从生成器返回调用函数 main_01
    ---g_01-02---                  通过调用者main_01,我们send('android'),向生成器传送一个值,生成器接受这个值,并向下执行
    ---g_01---:Android             执行生成器代码
    ---g_01---:Android             执行生成器代码
    ---g_01---:Android             执行生成器代码
    ---g_01---:Android             执行生成器代码
    ---g_01---:Android             执行生成器代码
    StopIteration                  生成器代码执行完毕,出发StopIteration异常,抛给send方法的调用者main_01函数
'''
'''
所以,我们不能在预激线程的代码中传入数据,应为那时生成器的代码还没执行到yield的位置,只有预激生成器,
让生成器执行到yield前停住。往后我们调用send传入数据,此时生成器才能接受我们传入的值


下面我们验证下
'''
def main_02():
    g=g_01()
    print('---main_01-01---') #代码执行位置标记
    # g.send(None) #我们的核心:预激生成器
    print('---main_01-02---')
    g.send('Android')
'''
执行:
    main_02()
输出结果:
    ---main_01-01---
    ---main_01-02---   #我们取消了传送send(None),生成器开始到第一个yield之间的代码没有执行
    Traceback (most recent call last):
      File "/home/qing/PythonWebApp/02_异步IO/02_asyncio案例/关于预激线程的探讨.py", line 48, in <module>
        main_02()
      File "/home/qing/PythonWebApp/02_异步IO/02_asyncio案例/关于预激线程的探讨.py", line 42, in main_02
        g.send('Android')
    TypeError: can't send non-None value to a just-started generator


所以,我们预激生成器的意义是将代码生成器代码在神奇的yield位置停住,这个生成器创建代码并不会将代码执行到yield位置),生成器准备接受参数
'''
'''
或许大家会对生成器到底是在yield的前面停住,还是在yield执行过程中停住这个问题有疑问,
下面我们来看下这两个例子,来看下生成器是如何执行yield的
'''
def gen_01():
    print('gen_01--before y1--')
    y1=yield 'yield_y1'
    print('gen_01--after y1:{}--'.format(y1))

    print('gen_01--before y2--')
    y2=yield 'yield_y2'
    print('gen_01--after y2:{}--'.format(y2))

    print('gen_01--before y3--')
    y3=yield 'yield_y3'
    print('gen_01--after y3:{}--'.format(y3))

    return 'jet'

def main_01():
    g=gen_01()

    print('main_01--before s1--')
    s1=g.send(None)
    print('main_01--after s1:{}--'.format(s1))

    print('main_01--before s2--')
    s2=g.send('send_s2')
    print('main_01--after s2:{}--'.format(s2))

    print('mian_01--before s3--')
    s3=g.send('send_s3')
    print('main_03--after s3:{}--'.format(s3))

    print('main_01--before s4--')


    s4=None
    try:
        s4=g.send('s4')
        print('main_01--stop iteration:{}--'.format(s4))
    except StopIteration as e:
        print('main_01--Exception_StopIteration:{} --'.format(e))
'''
执行:

    main_01()
    
输出结果:

    main_01--before s1--
    gen_01--before y1--
        我们在调用者main中调用send预激生成器,然后程序跳到生成器中执行,
        生成器件执行到第一个yiled出停住,第一个yield右边的值返回给调用者main,程序跳回main执行
    main_01--after s1:yield_y1-- 
    main_01--before s2--
        调用者main接受生成器yield过来的参数,继续往下执行,直达执行到第二个send,程序跳转到生成器中执行
    gen_01--after y1:send_s2--
    gen_01--before y2--
        生成器从第一个卡住的yield位置向下执行,接收调用者main函数send过来的参数,然后继续往下执行,直到遇到二个yield,将第二个yield右边的值返回给调用者main,程序跳回main执行
    main_01--after s2:yield_y2--
    mian_01--before s3--
        调用者main接受生成器yield过来的参数,继续向下执行,直到执行到第三个send,程序跳转到生成器中执行
    gen_01--after y2:send_s3--
    gen_01--before y3--
        生成器从第二个卡住的yield位置向下执行,接受调用者main函数send过来的参数,然后继续向下执行,直到遇到第三个yield,将第三个yield右边的值返回给调用者main,程序跳回main执行
    main_03--after s3:yield_y3--
    main_01--before s4--
        调用者main接受生成器yield过来的参数,继续向下执行,直到执行到第四个send,程序跳转到生成器中执行
    gen_01--after y3:s4--
        生成器从第三个卡住的yield位置向下执行,接受调用者main函数send过来的参数,然后继续向下执行,直达全部执行完毕(return 'jet'),
        然后向上抛出StopIteration(这个异常的__str__返回'jet'的__str__,如果没有返回值,这个异常的__str__返回""),调用者main充当StopIteration的接盘侠 
    main_01--Exception_StopIteration:jet -- 
        调用者main函数,捕获异常并执行接下来的代码,直到执行完毕
        
'''

def gen_02():
    print('gen_02--before y1--')
    y1=yield 'yield_y1'
    print('gen_02--after y1:{}--'.format(y1))

    print('gen_02--before y2--')
    y2=yield 'yield_y2'
    print('gen_02--after y2:{}--'.format(y2))

    print('gen_02--before y3--')
    y3=yield 'yield_y3'
    print('gen_02--after y3:{}--'.format(y3))


def main_02():
    g=gen_02()

    print('main_02--before s1--')
    s1=g.send(None)
    print('main_02--after s1:{}--'.format(s1))

    print('main_02--before s2--')
    s2=g.send('send_s2')
    print('main_02--after s2:{}--'.format(s2))

    print('mian_02--before s3--')
    s3=g.send('send_s3')
    print('main_02--after s3:{}--'.format(s3))

    print('main_02--before s4--')


    s4=None
    try:
        s4=g.send('s4')
        print('main_02--stop iteration:{}--'.format(s4))
    except StopIteration as e:
        print('main_02--Exception_StopIteration:{} --'.format(e))
'''
执行:
    main_02()
输出:
    main_02--before s1--
    gen_02--before y1--
    main_02--after s1:yield_y1--
    main_02--before s2--
    gen_02--after y1:send_s2--
    gen_02--before y2--
    main_02--after s2:yield_y2--
    mian_02--before s3--
    gen_02--after y2:send_s3--
    gen_02--before y3--
    main_02--after s3:yield_y3--
    main_02--before s4--
    gen_02--after y3:s4--
        生成器从第三个卡住的yield位置向下执行,接受调用者main函数send过来的参数,然后继续向下执行,直达全部执行完毕,
        然后向上抛出StopIteration(这个生成器没有return返回值,则异常的__str__返回“”),调用者main充当StopIteration的接盘侠 
    main_02--Exception_StopIteration: -- 
        调用者main函数,捕获异常并执行接下来的所有代码
    
'''




'''
写在最后:
    调用者调用生成器的send,
        如果是第一次调用
            会从生成器代码的开始一直运行到遇到的第一个yield,并将yield右边的值返回给调用者,停在yield,程序执行由生成器代码切换到调用者代码
        如果是普通情况下的调用
            会跳掉生成器代码执行,生成器从当前卡住的yield开始将接受send的参数,并继续往下执行,直到遇到下一个yield  (yield_02), 
            并将这个yield  (yield_02)的右边的值返回给调用者,生成器件停在yield (yield_02),程序跳动回调用者执行
        如果是最后一次调用
            也就是及接下来没有代码或者剩下的所有代码中没有yield(全部执行完也不会遇到yield),执行完后直接向调用者抛出StopIteration(如果生成器最有有return XX,则我们将XX包在StopIteration对象中返回给调用者)
'''

相关文章

  • 01-从生成器预激到send,yield交互流程

  • 协程

    从yield说起 当生成器执行到yield的时候,通过send方法向生成器传递一个值,生成器在收到传进来的值之后,...

  • 2019-07-02

    使用send唤醒生成器 如果一创建生成器就send会报错,因为没有yield,也没有ret去接收,但是可以send...

  • Python:yield 高级用法 send、yiled fro

    1. yield 中 send 用法 send 作用-- 生成器函数返回值给调用方;-- 调用方通过 send ...

  • 协程

    生成器语法 yield 一个对象返回这个对象 暂停这个函数等待下次next重新激活 send与yield的切换...

  • python的生成器和协程

    上面是一个简单的生成器,在第一次调用g.send(None)的时候,生成器开始从头一直执行到yield处(yiel...

  • python协程2:yield from 从入门到精通

    上一篇python协程1:yield的使用介绍了: 生成器作为协程使用时的行为和状态 使用装饰器预激协程 调用方如...

  • 生成器

    用send启动生成器(next不能传参,send可以) yield 使得函数可以返回一部分结果,暂停执行,如果是r...

  • Python协程

    目录:一、基于生成器的协程二、协程状态三、协程预激装饰器四、终止协程和异常处理五、协程返回值六、yield fro...

  • Python协程详解:从yield/send到yield fro

    Python中的协程发展历史分为三个阶段: 最初的生成器变形yield/send 引入@asyncio.corou...

网友评论

      本文标题:01-从生成器预激到send,yield交互流程

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