zoukankan      html  css  js  c++  java
  • yield from

    一、yield
    关于yield详细可参考我这篇文章

    下面是一个带yield的生成器:

    def gen_yield():
        while True:
            recv = yield
            do something with recv
    

    现在我们不单独使用gen_yield这生成器,而是通过另一个携程outer_yield完成必要的验证、设置等再去使用它

    def outer_yield():
        chiled_gen = gen_yield()
        chiled_gen.send(None) #准备上子携程
        
        do something just like setting or you want #在这儿做一些设置或者验证工作
        
        while True:
            recv = yield
            chiled_gen.send(recv) #把上面接收到的消息,发送到子携程处理
    

    以上可知,yield 只允许协程与外界直接交互而不能使得子协程与外界直接交互。而且,我们这里还没有考虑子协程抛出异常,返回等情况。

    yield form 应运而生来解决这个问题:

    def gen_yield():
        while True:
            recv = yield
            do something with recv
    
    def new_outer():
    
        do something you want
        yield from gen_yield()         #1 yield from 后必须跟generator object
    
    no = new_outer()
    no.send(None)  #2启动生成器
    

    这儿我们可以理解为#1 处yield from 把工作下发(委托)给了gen_yield()子生成器
    而当#2出外界开始send值与outer交互时,outer直接通过yield from把值发送给子生成器gen_yield执行
    这样就达到了外界直接与子生成器直接交互的功能。

    总结:

    1. 所有new_outer的实例作为调用者把值send过去,都等于直接发送给了子迭代器gen_yield,而子迭代器yield回来的值也登月直接给了调用者。意思就是nwe_outer委托gen_yield工作。
    2. 当new_outer实例调用send方法,就等于gen_yield子迭代器同步调用send方法,把值send到子迭代器内部yield。
    3. 当子迭代器gen_yield内部捕获到StopIteration时,子迭代器内部停止执行,开始执行委托者new_outer.
    4. 委托生成器有一个 throw() 方法可发送任何除了 GeneratorExit 的异常都将被直接发送给子迭代器 。同理,如果这次调用产生了 StopIteration 异常,那么委托生成器 new_outer 将被恢复执行
    5. 如果向委托生成器发送了 GeneratorExit 异常或者调用委托生成器的 close() 方法,那么首先子迭代器 b 的 close() 方法就会被调用(如果有的话)。随后,委托生成器就会引发 GeneratorExit 异常,从而退出
    6. 如果迭代器 gen_yield中有 return value ,那么当 子迭代器 执行 return 返回时,等价于 raise StopIteration(value)(迭代器总是通过引发StopIteration 异常停止),之后该 value 将成为 yield from 表达式值。
    7. 在任意运行时刻,如果迭代器gen_yield抛出了未捕获的异常,那么该异常将会被传播给委托生成器new_outer
    带return值的列子
    >>> def inner_gen():
    ...    sum_all = 0
    ...    while True:
    ...        x = yield
    ...        print('recv : {0}'.format(x))
    ...        if x is None:
    ...            return sum_all
    ...        sum_all = sum_all + x
    ...
    >>> def outer():
    ...    while True:
    ...        sum_all = yield from inner_gen()
    ...        print('sum_all is: {0}'.format(sum_all))
    ...        print('outer 执行完毕')
    ...
    
    >>> out = outer()
    >>> out.send(None)  # 准备好协程
    >>> for i in range(3):
    ...     out.send(i)    
    ...
    recv: 0
    recv: 1
    recv: 2
    >>> out.send(None)  # 停止子协程
    recv : None
    sum_all is: 3
    outer 执行完毕
    >>> for i in range(5):
    ...     out.send(i)
    ...
    recv: 0
    recv: 1
    recv: 2
    recv: 3
    recv: 4
    >>> out.send(None)
    recv: None
    sum_all is: 10
    outer 执行完毕
    
    >>> out.throw(TypeError)  # TypeError 来自 inner_gen 函数
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in outer
      File "<stdin>", line 4, in inner_gen
    TypeError
    

    使用 send() 方法发送的值将被直接发送字生成器 inner_gen() 中了,throw() 同理。当子迭代器返回时,return 后的值成为 yield from 表达式的值。

    yield from 允许外界与子协程直接交互,这样就允许代码重构:把一部分包含 yield 的代码放到另外的函数,再使用 yield from 调用该迭代器。这样就实现委托工作了

  • 相关阅读:
    使用FolderBrowserDialog组件选择文件夹
    使用OpenFileDialog组件打开多个文
    使用OpenFileDialog组件打开对话框
    获取弹出对话框的相关返回值
    PAT 甲级 1139 First Contact (30 分)
    PAT 甲级 1139 First Contact (30 分)
    PAT 甲级 1138 Postorder Traversal (25 分)
    PAT 甲级 1138 Postorder Traversal (25 分)
    PAT 甲级 1137 Final Grading (25 分)
    PAT 甲级 1137 Final Grading (25 分)
  • 原文地址:https://www.cnblogs.com/shiqi17/p/9444675.html
Copyright © 2011-2022 走看看