code1:
def af():
a=65
try:
yield a
finally:
print('end')
print(af().next())
code2:
def af():
a=65
try:
yield a
finally:
print('end')
g=af()
print(g.next())
the result of code1 is:
end
65
but the result of code2 is:
65
end
In snippet 1, when Python executes
print(af().next())
it gets through
af().next()
and then the generator object's reference count falls to 0. At this point, Python calls the generator's close
method to force finally
blocks and __exit__
methods to run, so the finally
block prints end
.
Then the print
part of print(af().next())
runs and prints 65
.
In snippet 2, when Python executes
print(g.next())
the generator object is kept alive by the reference from the g
variable, so the finally
block doesn't run at this point, and Python prints 65
.
Then, during interpreter shutdown, the generator's refcount falls to 0, and close
triggers the finally
block, which prints end
. This is not guaranteed to happen - Python does not guarantee that objects alive at interpreter shutdown will have their destructors called - but it happened.