Python——在不同的使用者中使用一个生成器

Python——在不同的使用者中使用一个生成器,python,generator,yield,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(co

我有一台发电机供不同的消费者使用。后者中的每一个都可以从生成器中获取不同的项,因此我不能只使用一个大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']

用返回列表中添加的测试更新下面的已接受的解决方案是可以的,只是我过度简化了示例代码,客户机中可能有许多后续语句。我现在需要的是一种在第一次StopIteration被提出后立即从客户机函数返回的方法。因此,我添加了一个关于的后续问题。

在while循环的第二次迭代中,服务器生成器只需再生成2个项目,客户端函数在尝试获取3个元素时将触发StopIteration异常

您需要在客户端函数中处理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循环;如果客户端未返回元素,则服务器必须为空:

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重新实现您的服务器:

您可以使用以下方法来处理您的客户:

from itertools import islice

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

在while循环的第二次迭代中,服务器生成器只需再生成2个项目,客户机函数将在尝试获取3个元素时触发StopIteration异常

您需要在客户端函数中处理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循环;如果客户端未返回元素,则服务器必须为空:

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重新实现您的服务器:

您可以使用以下方法来处理您的客户:

from itertools import islice

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

难道你不应该用另一条看起来像餐=clientcourse,2的线来吃甜点吗?你已经做对了。问题是,您的代码无法处理比您预期的更短的iterables;用餐=客户课程,如果只剩下2项,则3项失败。您可以考虑使用ItRealths.ISLICE;islicemyiterable,0,4将返回最多4个值,但如果返回的值较少,则不会失败。您是否应该使用另一行类似于“餐=clientcourse,2”的行来消费甜点?您已经正确地执行了。问题是,您的代码无法处理比您预期的更短的iterables;用餐=客户课程,如果只剩下2项,则3项失败。您可以考虑使用ItRealths.ISLICE;islicemyiterable,0,4将返回最多4个值,但如果返回的值较少,则不会失败。我明白你的意思,但现在,我们如何知道在while循环级别StopIteration中没有更多的项被客户端吞没了?@greendiod:Test如果客户端返回空列表,我想。我需要额外的计算来计算客户列表,但我同意你的观点,在简化的例子中,islice就足够了。事实上,在返回列表中添加测试的解决方案是可以的,只是我过度简化了示例代码,客户机中还有许多后续语句。我现在需要的是一种在第一次StopIteration启动后立即从客户端返回的方法。我明白你的意思,但是现在,我们怎么知道在while循环级别StopIteration已被客户端吞没的情况下,没有其他项了?@greendiod:Test如果客户端返回空列表,我想。我需要额外的计算来计算客户列表,但我同意你的观点,在简化的例子中,islice就足够了。事实上,在返回列表中添加测试的解决方案是可以的,只是我过度简化了示例代码,客户机中还有许多后续语句。我现在需要的是一种在第一次StopIteration启动后立即从客户机返回的方法。