I posted this to my blog at http://michaelspeer.blogspot.com/2007/11/context-manager-for-temporary.html.
I decided to forward it onto the list for comments. I thought someone might find it interesting. *** This is very much a fragile hack at the moment. It's an interesting idea I think. I was disappointed when I initially found that the with_statement syntax does not restore the value of the `as var` upon completion. This made doing something along the lines of with temporarily_memoized( func ) : for datum in data : func( datum ) unattainable. Well, just a lot hackier actually. Thus temporarily_memoized( ... ) was born : #!/usr/bin/python # a context manager for temporarily turning any function into # a memoized version of itself. from __future__ import with_statement import contextlib , sys , types def memoize ( func ) : """ In haskell mutability must be handled explicitly. Only fair that Python do the same to transparent functionality """ remembered = {} def memoized ( *args ) : """ memoized version of function """ if args in remembered : return remembered[ args ] else : new = func( *args ) remembered[ args ] = new return new return memoized @contextlib.contextmanager def temporarily_memoized ( func ) : """ memoize the given function for the duration of this block save anything in the local variables that gets in the way of using this so that it can be restored afterward , the memoized version is found in the locals. use on actual functions only. no members. """ # this is being called, there has to be a frame above it frame = sys._getframe().f_back.f_back if func.func_name in frame.f_locals : f = frame.f_locals[ func.func_name ] frame.f_locals[ func.func_name ] = memoize( func ) try : # this hack replaces whatever in the local scope # has the name of the variable. if you try to use # the 'as whatever' portion of the syntax , you # are doing it wrong yield None finally : frame.f_locals[ f.func_name ] = f else : frame.f_locals[ func.func_name ] = memoize( func ) try : yield None finally : del frame.f_locals[ func.func_name ] def fib(n): """ biggus fibbus """ if n == 0 or n == 1: return n else: return fib(n-1) + fib(n-2) if __name__ == '__main__' : print fib.__doc__ with temporarily_memoized( fib ) : print fib.__doc__ for i in xrange( 36 ) : print "n=%d => %d" % (i, fib(i)) print fib.__doc__ print fib.__doc__ outputs : biggus fibbus memoized version of function n=0 => 0 ..... n=35 => 9227465 memoized version of function biggus fibbus -- http://mail.python.org/mailman/listinfo/python-list