最后更新于
最后更新于
yield from使用在生成器的定义过程中, 与yield对比, yield from subgen()
这种形式, 可以从子生成器中获取结果, 更准确的说是子生成器subgen
会获得控制权, 并且把产出的值直接传给的调用方, 而不再经过生成器, 这种形式:
方便了生成器的嵌套使用
调用方可以直接调用子生成器
在子生成器执行时, 生成器gen
会阻塞, 等待子生成器subgen
交换控制权.
事实上, yield from会调用紧跟对象的__iter__
方法, 因此对于任何可迭代的对象, 如str
, list
等都可以配合yield from
使用, 代替繁琐的循环:
输出为:
对主函数直接调用的生成器, 以及上文中的子生成器, 正式定义为:
调用方: 调用委派生成器的客户端代码
委派生成器: 包含yield from表达式的生成器函数
子生成器: 从yield from部分获取的生成器
三者是一种层级递进关系.
yield from的主要功能是打开双向通道, 把最外层的调用方与最内层的子生成器连接起来, 使两者可以直接发送和产出值, 还可以直接传入异常, 而不用在中间的协程添加异常处理的代码.
委派生成器在yield from表达式处暂停时, 调用方可以直接把数据发给子生成器, 子生成器再把产出的值发送给调用方.
子生成器返回之后, 解释器会抛出StopIteration异常, 并把返回值附加到异常对象上, 委派生成器恢复.
从一个例子中感受yield from
的执行过程.
执行结果为:
上面的代码展示了yield from的基础用法, 委派生成器相当于管道, 所以可以把任意数量的委派生成器连接在一起. 而且委派生成器中的子生成器内部也可以调用生成器, 从而加深了调用关系, 只需要最终以一个只是用yield表达式的生成器结束.
子生成器产出的值都直接传给委派生成器的调用方
使用send
方法发给委派生成器的值都直接传给子生成器, 如果发送的值是None, 那么会调用子生成器的 next()方法; 如果发送的值不是None, 那么会调用子生成器的send
方法.
如果调用的方法抛出StopIteration异常, 那么委派生成器恢复运行
任何其他异常都会向上冒泡, 传给委派生成器
生成器退出时, 委派生成器/子生成器中的return表达式expr
会触发StopIteration(expr)
, 将异常抛出
yield from
表达式的值是子生成器终止时传给StopIteration异常的第一个参数
传入委派生成器的异常, 除了GeneratorExit之外都传给子生成器的throw
方法. 如果调用throw
方法时抛出StopIteration异常, 委派生成器恢复运行. StopIteration之外的异常会向上冒泡, 传给委派生成器
如果把GeneratorExit异常传入委派生成器, 或者在委派生成器上调用close
方法, 那么在子生成器上调用close
方法(如果子生成器有的话).
如果调用close
方法导致异常抛出, 那么异常会向上冒泡, 传给委派生成器
否则, 委派生成器抛出GeneratorExit异常