Python -- 在多个消费者中使用一个生成器
我有一个生成器,供不同的消费者使用。每个消费者可以从这个生成器中获取不同的项目,所以我不能只用一个大循环来处理所有的项目。我想要的是完全消费掉这个生成器。该怎么做呢?
# -*- coding: utf-8 -*-
MEALS = ['Oysters', 'Consommé', 'Lamb', 'Rice', 'Sirloin','Banana', 'Pastry']
def server():
for n in MEALS:
yield n
def client(course, take):
meal = []
for _ in range(take):
some_meal = next(course)
meal.append(some_meal)
return meal
if __name__ == '__main__':
#print("Available meals: ", list(MEALS))
course = server()
try:
while True:
meal = client(course, 3)
print("First client: ", meal)
meal = client(course, 2)
print("Second client: ", meal)
except StopIteration:
pass
当前输出:
First client: ['Oysters', 'Consommé', 'Lamb']
Second client: ['Rice', 'Sirloin']
但是甜点在哪里呢??
期望输出:
First client: ['Oysters', 'Consommé', 'Lamb']
Second client: ['Rice', 'Sirloin']
First client: ['Banana', 'Pastry']
更新 下面接受的解决方案加上对返回列表的测试是可以的,只是我简化了示例代码(在client
中可能会有很多next
语句)。我现在需要的是一种方法,让client
函数在第一次抛出StopIteration
时立即返回。所以我添加了一个后续问题,关于在遇到第一次StopIteration时退出函数的最佳方法。
1 个回答
4
在第二次执行while
循环时,server
这个生成器只剩下2个可以提供的项目,而当client()
函数尝试获取3个元素时,就会引发StopIteration
异常。
你需要在client()
函数中处理StopIteration
异常:
def client(course, take):
meal = []
for _ in range(take):
try:
some_meal = next(course)
meal.append(some_meal)
except StopIteration:
pass
return meal
现在,既然客户端会处理StopIteration
,你就得以不同的方式处理while
循环;如果client()
没有返回任何元素,那说明你的server
一定是空的:
while True:
meal = client(course, 3)
if not meal:
break
print("First client: ", meal)
meal = client(course, 2)
print("Second client: ", meal)
if not meal:
break
你在这里缺少了一些来自Python标准库的小技巧。你可以用iter()
重新实现你的server
:
def server():
return iter(MEALS)
而且你可以使用itertools.islice()
来处理你的客户端:
from itertools import islice
def client(course, take):
return list(islice(course, take))