FlashDD
FlashDD

Reputation: 438

Memoize a function which uses instance attributes

I'm new to python and i couldn't find an answer online. lets say i have a method which does some computation and returns a string

def output(self)
     a=self.some_long computation1()
     b=self.some_long computation2()
     c=self.some_attribute
     some_computatuion_inside
     return output_string

I'm using this function in a few places and want to memoize it, but since it takes no arguments and depends on instance attributes which can change between calls, im not sure how to proceed,

i realize i can write my own memoization function which will check if those attributes changed, but that seems incorrect, because that would be specific to this function only and i would like maybe in the future to do the same for other functions

Upvotes: 1

Views: 375

Answers (2)

Bakuriu
Bakuriu

Reputation: 101979

Decorators can compute the key based on any argument. Any instance method has an argument, that is self, and it's pretty easy to use to obtain a memoize decorator for methods:

CACHE = {}

def memoize(*attributes):
    def decorator(meth):
        def wrapper(self):
            key = tuple(getattr(self, attr) for attr in attributes)
            try:
                result = CACHE[key]
            except KeyError:
                result = CACHE[key] = meth(self)
            return result
        return wrapper
    return decorator

Usage:

class Factorial(object):
    def __init__(self, n):
        self.n = n
    @memoize('n')
    def compute(self):
        if self.n in (0,1): return self.n
        else:
            return Factorial(self.n-1).compute() + Factorial(self.n-2).compute()


f = Factorial(100)

f.compute()
Out[4]: 354224848179261915075L

Upvotes: 1

Andy Hayden
Andy Hayden

Reputation: 375585

One way is to pull out the variables (assuming they are hashable) and make it a static method:

@staticmethod
def output_static(a, b, c)
     some_computatuion_inside
     return output_string

And then call it from within the class as:

self.output_static(a=self.some_long_computation1()
                   b=self.some_long_computation2()
                   c=self.some_attribute)

You could also use the techinque to memoize both some_long_computation1 and some_long_computation1.

If you wanted you could write an intermediary helper function which would simply call the (memomized) static method:

def output(self):
    return self.output_static(a=self.some_long_computation1()
                              b=self.some_long_computation2()
                              c=self.some_attribute)

Upvotes: 1

Related Questions