How to memoize/cache property access?

thebjorn BjornSteinarFjeldPettersen at gmail.com
Thu Dec 20 11:02:24 EST 2007


I seem to be writing the following boilerplate/pattern quite
frequently to avoid hitting the database until absolutely necessary,
and to only do it at most once:

class Foo(object):
    @property
    def expensive(self):
        if not hasattr(self, '_expensiv'):
            self._expensive = <insert expensive db call here>
        return self._expensive

it's a bit verbose, and it violates the DRY (Don't Repeat Yourself)
principle -- and it has on at least one occasion resulted in really
slow code that produces the correct results (did you spot the typo
above?).

It would have been nice to be able to write

class Foo(object):
    @property
    def expensive(self):
        self.expensive = <insert expensive db call here>
        return self.expensive

but apparently I "can't set [that] attribute" :-(

I'm contemplating using a decorator to hide the first pattern:

def memprop(fn):
    def _fn(self):  # properties only take self
        memname = '_' + fn.__name__
        if not hasattr(self, memname):
            setattr(self, memname, fn(self))
        return getattr(self, memname)
    return property(fget=_fn, doc=fn.__doc__)

which means I can very simply write

class Foo(object):
    @memprop
    def expensive(self):
        return <insert expensive db call here>

I'm a bit hesitant to start planting home-grown memprop-s all over the
code-base though, so I'm wondering... does this seem like a reasonable
thing to do? Am I re-inventing the wheel? Is there a better way to
approach this problem?

-- bjorn



More information about the Python-list mailing list