Я думаю, что вы можете избежать этого, принося что-то особенное.
Я должен был создать свой собственный работающий пример, чтобы показать, что я имею в виду:
def fetch_one(n):
lst = [[1,2,3], [4,5,6], [7,8,9]][n]
for x in lst:
if x == 6:
yield 'StopAll'
return
yield x
def work():
n = 0
in_progress = True
while in_progress:
numbers_iterator = fetch_one(n)
for x in numbers_iterator:
if x == 'StopAll':
in_progress = False
break
print('x =', x)
n += 1
work()
Выход:
x = 1
x = 2
x = 3
x = 4
x = 5
Мне нравится это больше, чем self.finished
или декоратор, подобный тому, который вы построили, но я думаю, что что-то лучшее можно найти. (Может быть, этот ответ поможет вам в этом).
Обновление: Гораздо более простым решением может быть преобразование fetch_one
в класс с собственным флагом finised
.
Декораторский подход к этому решению может быть:
class stopper(object):
def __init__(self, func):
self.func = func
self.finished = False
def __call__(self, *args, **kwargs):
for x in self.func(*args, **kwargs):
if x == 6:
self.finished = True
raise StopIteration
yield x
else:
self.finished = True
По сути, вам уже все равно, как работает fetch_one
, только если с выходами все в порядке или нет.
Пример использования:
@stopper
def fetch_one(n):
lst = [[1,2,3], [4,5,6], [7,8,9]][n]
#lst = [[1,2,3], [], [4,5,6], [7,8,9]][n] # uncomment to test for/else
for x in lst:
yield x
def work():
n = 0
while not fetch_one.finished:
for x in fetch_one(n):
print('x =', x)
n += 1