不确定为什么 "yield from" 不处理 StopIteration
Unsure of why the StopIteration isn't handled by "yield from"
查看 "Fluent Python" 书中解释 yield from
的 "bidirectional tunnel" 功能的以下示例代码,我有以下问题。
from collections import namedtuple
Result = namedtuple('Result', 'count average')
# the subgenerator
def averager(): # <1>
total = 0.0
count = 0
average = None
while True:
term = yield # <2>
if term is None: # <3>
break
total += term
count += 1
average = total/count
return Result(count, average) # <4>
# the delegating generator
def grouper(results, key): # <5>
while True: # <6>
results[key] = yield from averager() # <7>
# the client code, a.k.a. the caller
def main(data): # <8>
results = {}
for key, values in data.items():
group = grouper(results, key) # <9>
next(group) # <10>
for value in values:
group.send(value) # <11>
group.send(None) # important! <12>
print("wrapped up grouper")
print(results)
data = {
'girls;kg':
[40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5],
'girls;m':
[1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43],
'boys;kg':
[39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
'boys;m':
[1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46],
}
当我将上面的委托生成器替换为以下委托生成器时,为什么会出现 StopIteration
异常?
def grouper(results, key):
results[key] = yield from averager()
根据我目前所了解的情况,理论上删除 while True
应该没问题。 group.send(None)
会导致 averager()
协程 break
和 return Result(...)
,这将被传递给委托生成器。然后委托生成器将通过将 Result(...)
分配给 results[key]
来完成。
但实际情况如下。
Traceback (mostrecent call last):
File "coroaverager3.py", line 111, in <module>
main(data)
File "coroaverager3.py", line 83, in main
group.send(None) # important! <12>
StopIteration
有什么见解吗?
委派生成器分配给 results[key]
是对的,但这样做并没有 完成 。它的执行继续进行,因为它没有地方可以暂停。当然,它立即从末尾掉下来,导致 send(None)
提高 StopIteration
(因为没有 value(来自 yield
)至 return).
while True:
是一种添加另一个暂停位置的愚蠢方式; yield from
之后的一个额外的 yield
会更明显一些。 (如果客户端并不总是知道执行何时完成,它可以提供与内部生成器提供的值不同的值。)
查看 "Fluent Python" 书中解释 yield from
的 "bidirectional tunnel" 功能的以下示例代码,我有以下问题。
from collections import namedtuple
Result = namedtuple('Result', 'count average')
# the subgenerator
def averager(): # <1>
total = 0.0
count = 0
average = None
while True:
term = yield # <2>
if term is None: # <3>
break
total += term
count += 1
average = total/count
return Result(count, average) # <4>
# the delegating generator
def grouper(results, key): # <5>
while True: # <6>
results[key] = yield from averager() # <7>
# the client code, a.k.a. the caller
def main(data): # <8>
results = {}
for key, values in data.items():
group = grouper(results, key) # <9>
next(group) # <10>
for value in values:
group.send(value) # <11>
group.send(None) # important! <12>
print("wrapped up grouper")
print(results)
data = {
'girls;kg':
[40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5],
'girls;m':
[1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43],
'boys;kg':
[39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
'boys;m':
[1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46],
}
当我将上面的委托生成器替换为以下委托生成器时,为什么会出现 StopIteration
异常?
def grouper(results, key):
results[key] = yield from averager()
根据我目前所了解的情况,理论上删除 while True
应该没问题。 group.send(None)
会导致 averager()
协程 break
和 return Result(...)
,这将被传递给委托生成器。然后委托生成器将通过将 Result(...)
分配给 results[key]
来完成。
但实际情况如下。
Traceback (mostrecent call last):
File "coroaverager3.py", line 111, in <module>
main(data)
File "coroaverager3.py", line 83, in main
group.send(None) # important! <12>
StopIteration
有什么见解吗?
委派生成器分配给 results[key]
是对的,但这样做并没有 完成 。它的执行继续进行,因为它没有地方可以暂停。当然,它立即从末尾掉下来,导致 send(None)
提高 StopIteration
(因为没有 value(来自 yield
)至 return).
while True:
是一种添加另一个暂停位置的愚蠢方式; yield from
之后的一个额外的 yield
会更明显一些。 (如果客户端并不总是知道执行何时完成,它可以提供与内部生成器提供的值不同的值。)