Memoization/Caching of Instance Methods

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Mark E. Fenner

    #1

    Memoization/Caching of Instance Methods

    In the code below, the class DifferentCache utilizes three different
    memoization (caching) strategies. Neither the function Memoize1 or
    the class Memoize2 will be adequate for all three of these cases (I
    intend these to be used as, for example,
    getInstanceValu eFunction = Memoize1(getIns tanceValueFunct ion)
    within the DifferentCache class definition).


    Memoize1 will have problems with getMemberValueF unction b/c it
    will try to generate a cache key for (self, 'arg1', 'arg2') whereas
    the actual values only depend on ('val1', 'val2') (though this may be
    more of a nuisance then an error).

    Memoize2 will have problems with getInstanceValu eFunction b/c
    instantiating Memoize2 will cause 'self' to refer to the Memoize2
    object and not to the DifferentCache object when computing the desired
    function (and worse yet, since the self that does reference
    DifferentCache is bound to the DifferentCache. getInstanceValu eFunction
    it is not even passed in as an argument when Memoize2.__call __ is
    executed .... apologies if my terminology is off). Actually, would
    this problem apply to any use of Memoize2 to any instance method?
    Also, for any of these memoizations, there is only 1 self so we really
    don't need it as a cache key.

    Both Memoize methods will have problems, in addition, b/c the hashing
    for an object is based on __str__ which should also be Memoized --
    that is, there is a circular dependency of __hash__ on __str__ and of
    __str__ on __hash__. Perhaps a generator that computed the value the first
    time and then subsequently return that value from a stored variable?

    Obviously, you could deal with these problems by simply keeping each
    individual cacheing strategy for the different methods. However, can
    anyone see how to unify these into a common cacheing mechanism? Or,
    can it be handled by some careful rewriting of how the functions
    (methods) are called?


    #
    # from ?? on comp.lang.pytho n
    #
    def Memoize1(func):
    cache = {}
    def _internal(*args ):
    if cache.has_key(a rgs):
    return cache[args]
    else:
    ans = cache[args] = func(*args)
    return ans
    return _internal

    #
    # from Peter norvig on comp.lang.pytho n
    #
    class Memoize2:
    def __init__(self, fn):
    self.cache={}
    self.fn=fn
    def __call__(self,* args):
    if self.cache.has_ key(args):
    return self.cache[args]
    else:
    object = self.cache[args] = self.fn(*args)
    return object


    #
    # an example class
    #
    class DifferentCache:
    def __init__(self, value):
    self.value = value
    self.complexVal ueCache = {}

    def getInstanceValu eFunction(self) :
    try:
    value = self.instanceVa lueCache
    except KeyError:
    value = self.instanceVa lueCache = someFunction(se lf)
    return value

    def getMemberValueF unction(self, other1, other2):
    try:
    value = self.complexVal ueCache[other]
    except KeyError:
    value = self.complexVal ueCache[other] = \
    someOtherFuncti on(self, other1, other2))
    return value

    def __str__(self):
    try:
    strValue = self.stringCach e
    except AttributeError:
    strValue = self.stringCach e = str(self.value)
    return strValue

    def nonCachedFuncti on(self):
    return yetAnotherFunct ion(self)

    def __hash__(self):
    return str.__hash__(st r(self))


    #
    # Desired rewrite or so
    #
    class DifferentCache:
    def __init__(self, value):
    self.value = value

    @Memoized
    def getInstanceValu eFunction(self) :
    return someFunction(se lf)

    @Memoized
    def getMemberValueF unction(self, other1, other2):
    return someOtherFuncti on(self, other1, other2)

    @Memoized
    def __str__(self):
    return str(self.value)

    def nonCachedFuncti on(self):
    return yetAnotherFunct ion(self)

    def __hash__(self):
    return str.__hash__(st r(self))

    Note, the various functions within the instance methods are meant to
    represent some arbitrary code executed on and computing values from the
    various arguments.

Working...