[Python-Dev] Object finalization for local (ie function) scopes
Oliver Schoenborn
oliver.schoenborn at utoronto.ca
Sun Jun 13 14:49:08 EDT 2004
> > The technique itself can be summarized as follows:
> >
> > - Create a function that wraps a try/finally around the function of
interest
> > - Make class whose instances need "cleanup" automatically tell the
function
> > in which they were created (the "function of interest" above) that they
> > should be cleaned up upon function exit. This requires three things:
>
> I claim that this might not be possible to do across different
> implementations of Python. It relies on the ability to look at the local
> variables of a caller of a function, and the Python language does not
> guarantee support for such a mechanism.
Actually it doesn't. The file I showed in my first post to python-dev used
the stack, plus the knowledge of what name was given to a local variable,
but it didn't need to "look at the local variables"; it looked at one
variable, of known name. I have a second implementation, below, that
requires neither stack, nor local, and is faster.
> > tied to the function. But there are other possibilities. E.g. instead of
> > creating a function attribute, the ScopeGuardian could use a global
stack of
> > list of objects. An instance of NeedsFinalization would use the top list
of
> > the stack to add a reference to istelf there.
>
> In that implementation, how would you know how many objects to cleanup?
See my reply to your last post where you ask same question. However, as to
this new implementation, I paste it in at the end of the post.
> Yes, but I have no reason to believe you an implementation is possible
> until I have seen an implementation.
> It might be that an implementation of the feature would be very
> expensive even if not used, in which case the feature also would not
> be acceptable for inclusion in Python.
I'm doing some timing tests, I should have them tonight with a bit of luck.
> However, this is probably the time to ask for a PEP that properly
> describes the API and the semantics of the feature.
In time... I'd like a couple more opinions if possible. I'm surprised there
hasn't been more given how fundamental the problem of RAII is in Python.
Oliver
----------- New implementation for scope.py --------------
# Note: comments and tests are in module, but not reproduced here for space
import sys
def ScopeGuarded(func):
return lambda *args, **kwargs: ScopeGuardian(func, *args, **kwargs)
_funcStack = []
class NeedsFinalization:
def __init__(self):
print '\n%s: being created' % repr(self)
self.__finalized = False
try: _funcStack[-1].append(self)
except IndexError:
raise RuntimeError, "Forgot to scope-guard function? "
def finalizeMaster(self):
print '%s: Finalize() being called' % repr(self)
self._finalize()
self.__finalized = True
def __del__(self):
try:
problem = not self.__finalized
except AttributeError:
msg = '%s: NeedsFinalization.__init__ not called for %s' \
% (repr(self), self.__class__)
raise RuntimeError, msg
if not problem:
print '%s: Finalized properly' % repr(self)
else:
print "Forgot to scope-guard function"
def ScopeGuardian(func, *args, **kwargs):
try:
scopedObjs = []
_funcStack.append(scopedObjs)
func(*args, **kwargs)
print 'Scoped variables created during call to %s: %s' \
% (func, scopedObjs)
finally:
_funcStack.pop()
scopedObjs.reverse() # destroy in reverse order from creation
for obj in scopedObjs:
obj.finalizeMaster()
def testBasic():
def func1():
ok = TestFree()
danger = TestDanger()
# test when forget to use ScopeGuardian
try:
hello = func1()
assert False, 'Expected exception not thrown!'
except RuntimeError, msg:
print 'Expected exception caught: ', msg
func1 = ScopeGuarded(func1)
func1()
def func2(objType):
dontKnow = objType()
func2 = ScopeGuarded(func2)
print "An RuntimeError exception will happen but be ignored: "
func2(TestDangerNoInit)
func2(TestDanger)
def testRecursive():
def recurse(n):
print 'Recurse(%s)' % n
danger = TestDanger()
ok = TestFree()
if n>0:
recurse(n-1)
else:
print 'recurse: Raising exception'
raise RuntimeError, "pretend exception thrown during recursion"
print '\nTesting that recursive does not work'
recurse = ScopeGuarded(recurse)
try:
recurse(3)
assert False, 'Expected exception not thrown!'
except RuntimeError, msg:
print 'Expected exception caught: ', msg
if __name__ == '__main__':
class TestFree:
def _finalize():
raise RuntimeError, 'finalize() not supposed to be called'
class TestDanger(NeedsFinalization):
def __init__(self):
NeedsFinalization.__init__(self)
def _finalize(self):
"""Override this. If you class inherits from a
class derived from NeedsFinalization, make sure to
call parent.finalize()."""
pass
class TestDangerNoInit(NeedsFinalization):
def __init__(self):
pass
def _finalize(self):
pass
testBasic()
testRecursive()
More information about the Python-Dev
mailing list