Python - 在各种消费者中使用一个生成器

时间:2014-03-03 14:50:26

标签: python generator yield

我有一个发电机供各种消费者使用。后者中的每一个都可以从生成器中获取不同的项目,因此我不能只使用一个大的for循环来处理所有项目。我想要的是完全消耗发电机。怎么办呢?

# -*- 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']

UPDATE 下面接受的解决方案在返回的列表中添加了测试,但我已经过度简化了示例代码(next中可能有很多client个语句) 。我现在需要的是在第一个client被引发后立即从StopIteration函数返回的方法。所以我添加了关于the best way to exit a function upon hitting the first StopIteration的后续问题。

1 个答案:

答案 0 :(得分:4)

while循环的第二次迭代中,server生成器只有2个项可以产生,client()函数会触发StopIteration异常试图获得3个元素。

您需要处理StopIteration函数中的client()

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标准库的一些技巧。您可以使用server重新实现iter()

def server():
    return iter(MEALS)

您可以使用itertools.islice()来处理您的客户:

from itertools import islice

def client(course, take):
    return list(islice(course, take))