问题
It's a follow-up to my 1 generator -- multiple consumers question. As StopIteration is the way the generator signals its exhaustion, unfortunately, I now have many exception-handling code littered all over the place in the client code (for every next() statement in the example below).
Is there a better way to exit with whatever value is built in meal upon hitting the first StopIteration exception?
def client(course, take):
meal = []
for _ in range(take):
try:
some_meal = next(course)
meal.append(some_meal)
except StopIteration:
pass
if take % 2 == 0:
try:
some_meal = next(course)
meal.append(some_meal)
except StopIteration:
pass
return meal
UPDATE Eventually, I ended up using 'itertools.islice' (see accepted solution below) as this function takes care of the StopIteration itself (see the for-loop equivalent implementation shown in the itertools doc. I prefer this solution over using next default second argument as it would imply checking each meal (still, I'd better use the latter than all the exception handling above).
回答1:
Just return directly in the first exception handler:
def client(course, take):
meal = []
for _ in range(take):
try:
some_meal = next(course)
meal.append(some_meal)
except StopIteration:
return meal
if take % 2 == 0:
try:
some_meal = next(course)
meal.append(some_meal)
except StopIteration:
pass
return meal
although I'd still use the standard library more here and not have to catch those StopIteration exceptions nearly as much:
from itertools import islice
def client(course, take):
meal = list(islice(course, take))
if take % 2 == 0:
some_meal = next(course, None)
if some_meal is not None:
meal.append(some_meal)
return meal
回答2:
Besides using islice, if I read the code correctly then it can be made even simpler:
def client(course, take):
if take % 2 == 0:
take += 1
return list(itertools.islice(course, take))
来源:https://stackoverflow.com/questions/22152578/python-exit-consumer-on-first-stopiteration