[Tutor] a caching function and argument passing
Remco Gerlich
scarblac@pino.selwerd.nl
Mon, 12 Jun 2000 11:26:37 +0200
On Mon, Jun 12, 2000 at 12:26:33AM -0700, Daniel Yoo wrote:
> After reading a little of Peter Norvig's "Paradigms of Artificial
> Intelligence", I've been playing around with equivalent programs in
> Python. One of these include a "caching function generator", a general
> program that caches the results of another:
>
> def makeCachedFn(fn):
> cache = {}
> def newfn(arg, fn=fn, cache=cache):
> if not cache.has_key(arg):
> cache[arg] = fn(arg)
> return cache[arg]
> return newfn
>
> As you can see, this will cache f(x), and works pretty well. For example:
>
> def factorial(x):
> if x == 0: return 1
> else: return x * factorial(x-1)
> factorial = makeCachedFn(factorial)
>
> does a very nice job in eliminating the cost of subsequent function
> calls.
>
> The problem I'm running into is in trying to generalize the generator for
> functions with an arbitrary number of arguments. I've tried to do
> something like:
>
> def newfun(*args, fn=fn, cache=cache)
>
> but in Python 1.52, this is an illegal signature, since optional
> parameters go at the end. I tried:
>
> def newfun(fn=fn, cache=cache, *args)
>
> but that apparently doesn't work either, because default arguments have
> priority in getting assigned first. Basically, I've been using the
> default arguments to simulate closures, but it's not quite working.
>
> Any help on this would be greatly appreciated. Thank you!
Here, I would make it into a class, default arguments can't do everything.
If you give a class a __call__ method, you can use its instances as
functions.
class makeCachedFn:
def __init__(self, fn):
self.fn = fn
self.cache = {}
def __call__(self, *args):
if not self.cache.has_key(args):
self.cache[args] = apply(self.fn, args)
return self.cache[args]
Now you can make __getitem__ too, and do for loops over the function :)
--
Remco Gerlich, scarblac@pino.selwerd.nl