[Python-ideas] Deterministic iterator cleanup

Ronan Lamy ronan.lamy at gmail.com
Fri Oct 21 15:20:55 EDT 2016


Le 21/10/16 à 14:35, Paul Moore a écrit :
>
> [1] As I understand it. CPython's refcounting GC makes this a
> non-issue, correct?

Wrong. Any guarantee that you think the CPython GC provides goes out of 
the window as soon as you have a reference cycle. Refcounting does not 
actually make GC deterministic, it merely hides the problem away from view.

For instance, on CPython 3.5, running this code:

#%%%%%%%%%

class some_resource:
     def __enter__(self):
         print("Open resource")
         return 42

     def __exit__(self, *args):
         print("Close resource")

def some_iterator():
     with some_resource() as s:
         yield s

def main():
     it = some_iterator()
     for i in it:
         if i == 42:
             print("The answer is", i)
             break
     print("End loop")

     # later ...
     try:
         1/0
     except ZeroDivisionError as e:
         exc = e

main()
print("Exit")

#%%%%%%%%%%

produces:

Open resource
The answer is 42
End loop
Exit
Close resource

What happens is that 'exc' holds a cyclic reference back to the main() 
frame, which prevents it from being destroyed when the function exits, 
and that frame, in turn, holds a reference to the iterator, via the 
local variable 'it'. And so, the iterator remains alive, and the 
resource unclosed, until the next garbage collection.


More information about the Python-ideas mailing list