cjm2671
cjm2671

Reputation: 19486

Python caching in objects

I've created an object called 'Frame'

class Frame:
    def __init__(self, image):
      self.image = image

    def gray(self):
      return cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)

Some operations, e.g. gray(), are expensive. I'd like to cache the result in the instance so that subsequent calls don't have to recalculate this. What's the cleanest way to do that?

Upvotes: 3

Views: 1318

Answers (3)

user890167
user890167

Reputation:

Could this not simply be done on instantiation?

class Frame:
    def __init__(self, image):
        self.image = image
        self.gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)

EDIT - Seems like a good time for a property?

class Frame(object):
    def __init__(self, image):
        self.image = image
        self._grey = None

    @property
    def grey(self):
        if self._grey is None:
            self._grey = solve_for_grey(self.image, stuff)
        return self._grey

Upvotes: 0

HarleyKwyn
HarleyKwyn

Reputation: 31

The best goto for problems involving this would be to use a memoize like function simple decorator solution can be found here: (http://code.activestate.com/recipes/578231-probably-the-fastest-memoization-decorator-in-the-/)

Upvotes: 2

Ry-
Ry-

Reputation: 225134

Pyramid uses this fantastic @reify decorator:

class reify(object):
    """ Use as a class method decorator.  It operates almost exactly like the
    Python ``@property`` decorator, but it puts the result of the method it
    decorates into the instance dict after the first call, effectively
    replacing the function it decorates with an instance variable.  It is, in
    Python parlance, a non-data descriptor.  An example:

    .. code-block:: python

       class Foo(object):
           @reify
           def jammy(self):
               print('jammy called')
               return 1

    And usage of Foo:

    >>> f = Foo()
    >>> v = f.jammy
    'jammy called'
    >>> print(v)
    1
    >>> f.jammy
    1
    >>> # jammy func not called the second time; it replaced itself with 1
    """
    def __init__(self, wrapped):
        self.wrapped = wrapped
        try:
            self.__doc__ = wrapped.__doc__
        except: # pragma: no cover
            pass

    def __get__(self, inst, objtype=None):
        if inst is None:
            return self
        val = self.wrapped(inst)
        setattr(inst, self.wrapped.__name__, val)
        return val

The docstring speaks for itself. =)

Upvotes: 4

Related Questions