> > 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()
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4