By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
444,100 Members | 2,979 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 444,100 IT Pros & Developers. It's quick & easy.

A context manager for temporary memoization.

P: n/a
I posted this to my blog at
http://michaelspeer.blogspot.com/200...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
Nov 29 '07 #1
Share this Question
Share on Google+
1 Reply


P: n/a
On Nov 29, 3:20 pm, "Michael Speer" <knome...@gmail.comwrote:
I posted this to my blog athttp://michaelspeer.blogspot.com/2007/11/context-manager-for-temporar....

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

Did you try to use temporarily_itemized inside a function? It might
not work as you think.

BTW, the name temporarily_memoized is superfluous. By definition,
whatever a context manager does is temporary, so using "temporarily"
in the name just adds a lot of letters and tells us nothing we didn't
already know.

Just call it memoized.
Carl Banks
Nov 29 '07 #2

This discussion thread is closed

Replies have been disabled for this discussion.

Browse more Python Questions on Bytes