The return value of your iterator function is used as the argument to the StopIteration
that it raises when it terminates:
>>> it = gen_test()
>>> next(it)
0
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
4
>>> next(it)
5
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration: [0, 1, 2, 3, 4, 5]
Only the first StopIteration
gets the specified value. Further attempts to iterate an empty generator will raise an empty exception:
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
You can extract the return value from a normal run of the iterator by avoiding for
loops and trapping the exception yourself:
it = gen_test()
while True:
try:
x = next(it)
# Do the stuff you would normally do in a for loop here
except StopIteration as e:
ret = e.value
break
print(ret)
All this is an awkward approach given that you have to decide between not using for
loops and not being able to return your accumulated data. Assuming that you're not OK with trying to accumulate the data externally (e.g. just doing list(gen_test())
), you can make your generator's state publicly accessible by using a class:
class gen_test:
def __init__(self):
self.l = []
self.it = iter(range(6))
def __iter__(self):
return self
def __next__(self):
i = next(self.it)
self.l.append(i)
return i
Now you can do something like
>>> it = gen_test()
>>> for x in it:
... print(x)
0
1
2
3
4
5
>>> print(it.l)
[0, 1, 2, 3, 4, 5]