using "private" parameters as static storage?

Peter Otten __peter__ at web.de
Fri Nov 14 03:49:04 EST 2008


Steven D'Aprano wrote:

> On Thu, 13 Nov 2008 19:52:13 -0700, Joe Strout wrote:
> 
>> Pity there isn't a way for a function to get a reference to itself
>> except by name.  Still, when you rename a method, you're going to have
>> to update all the callers anyway -- updating a couple of extra
>> references within the method is not that much extra effort.
> 
> I have come across a situation where this was a problem.
> 
> I was writing a bunch of different versions of the classic factorial and
> Fibonacci functions, some iterative, some recursive, some with caches,
> and some without. What I wanted to do was do something like this (for
> factorial):
> 
> 
> def iterative_without_cache(n):
>     product = 1
>     for i in xrange(1, n+1):
>         product *= i
>     return product
> 
> iterative_with_cache = decorate_with_cache(iterative_without_cache)
> 
> which works. But it doesn't work for the recursive version:
> 
> def recursive_without_cache(n):
>     if n <= 1:
>         return 1
>     else:
>         return n*recursive_without_cache(n-1)
> 
> recursive_with_cache = decorate_with_cache(recursive_without_cache)
> 
> for obvious reasons. Solution: the copy-and-paste anti-pattern. Good
> enough for test code, not for real work.
> 
> Now multiply the above by about a dozen slightly different recursive
> versions of the Fibonacci function, and you will see why it was a problem.

You can have Python do the copying for you:

def make_recursive(deco):
    @deco
    def recursive(n):
        if n <= 1:
            return 1
        return n * recursive(n-1)
    return recursive

def cached(f, _cache={}):
    def g(*args):
        try:
            result = _cache[args]
        except KeyError:
            result = _cache[args] = f(*args)
        return  result
    return g

r1 = make_recursive(lambda f: f)
r2 = make_recursive(cached)

Peter



More information about the Python-list mailing list