我正在使用yield from,但我不知道while对yield的影响。如果我将yield from放在一个while循环中,它工作得很好,但是当我同时取消这个循环时,一个异常就会发生。
final_result = {}
def sales_sum(pro_name):
total = 0
nums = []
while True:
x = yield
print(pro_name+" Sales volume: ", x)
if not x:
break
total += x
nums.append(x)
return total, nums
def middle(key):
while True:
final_result[key] = yield from sales_sum(key)
def middle2(key):
final_result[key] = yield from sales_sum(key)
def main(fun):
data_sets = { "A": [1200, 1500], "B": [28,55,98]}
for key, data_set in data_sets.items():
m = fun(key)
m.send(None)
for value in data_set:
m.send(value)
m.send(None)
if __name__ == '__main__':
main(middle) # work well
main(middle2) # StopIteration我希望main(middle2)能像main(middle)一样工作得很好,但有一个StopIteration例外。
发布于 2019-06-23 03:50:27
main中出现意外StopIteration异常的原因是,m.send(None)调用导致middle2生成器耗尽(子生成器sales_sum响应收到的False值而中断循环之后)。当生成器耗尽时,它会引发StopIteration。通常这是不可见的,因为您在for循环中使用迭代器,但在这种情况下,它会破坏您的代码。
有几种方法可以解决这个问题。一种是使用双参数调用next,而不是使用m.send(None)
next(m, None)这与m.send(None)的作用相同,但具有抑制StopIteration的额外好处。请注意,next调用中的None与send中的并不完全相同。在耗尽迭代器的情况下,它是默认返回值,而不是传入的值(使用next时,该值始终为None )。
另一种方法是更改middle2,使其不会在sales_sum生成器结束时结束。您可以在末尾添加一个额外的yield语句,这样当它的子生成器返回时,它会在分配给final_result之后最后一次生成控制权。
最后一个想法是用m.close()取代m.send(None)。这需要对final_result进行一些更改,因为close调用将在生成器中抛出一个GeneratorExit异常。如果你期望它,你可以使用它作为你要做的信号,而不是寻找一个错误的值:
def sales_sum(pro_name):
total = 0
nums = []
while True:
try:
x = yield
except GeneratorExit:
return total, nums
print(pro_name+" Sales volume: ", x)
total += x
nums.append(x)有了这一更改,middle2将不需要任何修改。
发布于 2019-06-23 03:49:58
sales_sum是一个有限迭代器。middle2只遍历它一次;middle尝试遍历多次。
https://stackoverflow.com/questions/56718368
复制相似问题