Python class decorators and methods and evaluation - django memoize

I have a working memoize decorator that uses the backend of a Django server to store the result of a function for a certain amount of time. I specifically apply this to a class method.

My decorator looks like this:

def memoize(prefix='mysite', timeout=300, keygenfunc=None):
    # MUST SPECIFY A KEYGENFUNC(args, kwargs) WHICH MUST RETURN A STRING
    def funcwrap(meth):

      def keymaker(*args, **kwargs):
        key = prefix + '___' + meth.func_name + '___' + keygenfunc(args, kwargs)
        return key

      def invalidate(*args, **kwargs):
        key = keymaker(*args, **kwargs)
        cache.set(key, None, 1)

      def newfunc(*args, **kwargs):
        # construct key
        key = keymaker(*args, **kwargs)

        # is in cache?
        rv = cache.get(key)

        if rv is None:
          # cache miss
          rv = meth(*args, **kwargs)
          cache.set(key, rv, timeout)

        return rv

      newfunc.invalidate = invalidate
      return newfunc
    return funcwrap

I use this in a class method, so something like:

class StorageUnit(models.Model):
  @memoize(timeout=60*180, keygenfunc=lambda x,y: str(x[0].id))
  def someBigCalculation(self):
    ...
    return result

The actual memoization process works great! That is, a challenge

myStorageUnitInstance.someBigCalculation()

uses cache correctly. Nice cool!

My problem is that I am trying to manually invalidate a record for a specific instance where I want to be able to run

myStorageUnitInstance.someBigCalculation.invalidate()

However, this does not work, because the "I" does not pass and, therefore, the key does not work. I get an IndexError: tuple index out of range error pointing to my lambda function, as shown earlier.

Of course, I can successfully call:

myStorageUnitInstance.someBigCalculation.invalidate(myStorageUnitInstance)

. "" , . Python , , "self"?

+3
2

, (. ). , , ( ). , , , - funcwrap ( , , .. __get__, , ), invalidate (, , , , " ", __get__), , , im_self ( ), .

( ;-) , , - , . , , - , , - - .

+2

AlexM, , :

# from django.whereever import cache
class memoize(object):
    def __init__(self,prefix='mysite', timeout=300, keygenfunc=None):
        class memo_descriptor(object):
            def __init__(self,func):
                self.func = func
            def __get__(self,obj,klass=None):
                key = prefix + '___' + self.func.func_name + '___' + keygenfunc(obj)
                class memo(object):
                    def __call__(s,*args,**kwargs):
                        rv = cache.get(key)
                        if rv is None:
                            rv = self.func(obj,*args, **kwargs)
                            cache.set(key, rv, timeout)
                        return rv
                    def invalidate(self):
                        cache.set(key, None, 1)
                return memo()
        self.descriptor = memo_descriptor
    def __call__(self,func):
        return self.descriptor(func)

. keygenfunc (*args,**kwargs) (instance), ( , someBigCalculation.invalidate , , ).

class StorageUnit(models.Model):
    @memoize(timeout=60*180, keygenfunc=lambda x: str(x.id))
    def someBigCalculation(self):
        return 'big calculation'

, , , - - .

-1

Source: https://habr.com/ru/post/1722646/


All Articles