A return statement in a Python 3.3+ generator doesn't do what you think it does. The value is not returned to the caller like in a normal function, but added as an attribute on the StopIteration exception the generator raises to signal that it is done iterating. The behavior you're seeing in your loop is unrelated.
First, lets understand the loop behavior. This comes down to a simple fact: The loop variable (e.g. i) doesn't go out of scope when a for loop ends:
for i in range(5): # this loop will print 0 through 4 print(i) print(i) # this line will print 4 again, since 4 it was the last value assigned to i
Your code is doing exactly this. The else clause you're using does nothing special, since you never break out of the loop. (Neftas's answer explains what an else attached to a loop is for.)
As for where the return value is going, you can find it if you iterate over your generator manually:
gen = test1() print(next(gen)) # prints 0 print(next(gen)) # prints 1 print(next(gen)) # prints 2 print(next(gen)) # prints 3 print(next(gen)) # prints 4 print(next(gen)) # prints set([0,1,2,3,4]) from the last yield statement try: next(gen) except StopIteration as e: print(e.value) # prints set([0,1,2,3,4]) from the return statement
This isn't a very common usage. The usual way of getting at the returned value is by using the result of a yield from expression in another generator:
def test3(): print(yield from test1())
This is a generator that yields all the same values as test1, but it also prints out the value that test1 returns.
I don't think the return idiom is terribly useful in most situations. yield from can be very useful in recursive or otherwise complex generators, but I've never found a need to return a value from one.
If you want more information about the yield from expression and the return value from generators, read PEP 380, which describes the new features that were added in Python 3.3.
elseonfordoes? It's explained in the docs.elseclause in aforloop. Found a nice blog post about it.try/except/else, where theelseclause is only executed if there are no exceptions.