Search code examples
pythonyieldfinally

why the results of below two codes are different?


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

Solution

  • 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.