Caching Property

Over the last couple of days, I have used a simple little pattern to cache long running idempotent instance methods.

Initially I decided to use a property which overwrote itself when called the first time.

import time

class Foo():

    def long_function(self):
        time.sleep(5)
        return 5

    @property
    def result(self):
        self.result = long_function()
        return self.result

In this example, the first time Foo.result is called, it calculates the desired value and binds it to the location of the property, then it returns what is now the bound value.

Although it is a bit hacky re-assigning it’s own value within the property method, this pattern actually works pretty well. That is until you use it on an object which inherits from object, which was an issue raised by my coworker, David.

When inheriting from object, ie:

class Foo(object):

Assigning the value of the property within the method raises an AttributeError.

Better pattern

With the first option proven to be shotty, a better solution is to assign the result to a private instance variable. Then rather than re-assigning the property, you can just check if the variable exists before returning it’s result.

import time

class Foo():

    def __init__(self):
        self._result = None

    def long_function(self):
        time.sleep(5)
        return 5

    @property
    def result(self):
        if not self._result:
            self._result = self.long_function()
        return self._result

I’m Eamon, a software developer out of Melbourne, Australia. You can email me, find me on Github or reach out on LinkedIn.