Excellent explanation by Mark Wooding. I would only like to add that the standard pythonic idiom in such cases seems to be the (ab)use of a default argument to the function, because these get evaluated at the definition time: def gen0(): for i in range(3): def gen1(i = i): yield i yield i, gen1()