更新:我已经在 python-ideas 上启动了一个线程来为此目的提出额外的语法或 stdlib 函数(即指定发送的第一个值yield from
)。到目前为止 0 回复... :/
如何截取子生成器的第一个产生的值,但将剩余的迭代委托给后者使用yield from
?
例如,假设我们有一个任意的双向生成器subgen
,并且我们想将它包装在另一个生成器gen
中。的目的gen
是拦截第一个产生的值subgen
并将生成的其余部分(包括发送的值、抛出的异常、.close() 等)委托给子生成器。
首先想到的可能是这样的:
def gen():
g = subgen()
first = next(g)
# do something with first...
yield "intercepted"
# delegate the rest
yield from g
但这是错误的,因为当调用者.send
在获得第一个值后返回给生成器时,它最终会作为yield "intercepted"
表达式的值,被忽略,而是作为第一个值g
接收,作为语义的一部分的。None
.send
yield from
所以我们可能会考虑这样做:
def gen():
g = subgen()
first = next(g)
# do something with first...
received = yield "intercepted"
g.send(received)
# delegate the rest
yield from g
但是我们在这里所做的只是将问题向后移了一步:一旦我们调用g.send(received)
,生成器就会恢复执行并且不会停止,直到它到达下一个 yield 语句,其值成为.send
调用的返回值. 所以我们还必须拦截并重新发送它。然后发送那个,然后再发送一次,依此类推......所以这行不通。
基本上,我要求的是一种yield from
自定义发送到生成器的第一个值的方法:
def gen():
g = subgen()
first = next(g)
# do something with first...
received = yield "intercepted"
# delegate the rest
yield from g start with received # pseudocode; not valid Python
...但不必重新实现yield from
我自己的所有语义。也就是说,费力且维护性差的解决方案是:
def adaptor(generator, init_send_value=None):
send = init_send_value
try:
while True:
send = yield generator.send(send)
except StopIteration as e:
return e.value
这基本上是一个糟糕的重新实现yield from
(它缺少对 , 等的处理throw
)close
。理想情况下,我想要一些更优雅、更少冗余的东西。