Entry
How do I release a resource used by a generator?
How+can+I+use+try-finally+in+a+generator%3F
May 31st, 2002 05:14
Michael Chermside, Daniel 'eikeon' Krech, Guido van Rossum, Michael Chermside
A generator is a function which creates an iterator... each time next()
is called on the iterator, the function in the generator runs until the
next yield statement. However, if the iterator stops "early" for some
reason, the generator may never run again! Because of this, you are not
permitted to use try-finally inside of a generator (at least not with a
yield inside the try section), since the program might never return to
complete the finally clause.
However, sometimes you DO want to have a resource which is released when
the generator completes. The simplest solution is to create a wrapper
around the generator, and release the generator when the wrapper object
is released (usually by dropping out of scope, although you could also
use del). The following session demonstrates the use of this technique:
Python 2.2.1 (#34, Apr 9 2002, 19:34:33) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from __future__ import generators
>>> def g():
... for i in range(5):
... yield i
...
>>> for x in g():
... print x
...
0
1
2
3
4
>>> def acquireResource():
... print 'Resource Acquired'
...
>>> def releaseResource():
... print 'Resource Released'
...
>>> class GeneratorWrapper:
... def __init__(self, generator):
... self.generator = generator
... acquireResource()
... def __del__(self):
... releaseResource()
... def __iter__(self):
... return self
... def next(self):
... return self.generator.next()
...
>>> def testNormalUse():
... w = GeneratorWrapper(g())
... for x in w:
... print x
...
>>> testNormalUse()
Resource Acquired
0
1
2
3
4
Resource Released
>>> def testAbortedUse():
... w = GeneratorWrapper(g())
... for x in w:
... print x
... if x > 2:
... return
...
>>> testAbortedUse()
Resource Acquired
0
1
2
3
Resource Released