Cached properties for classes

405 Views Asked by At

I like the cached_property module: https://pypi.python.org/pypi/cached-property

Is there a way to get cached properties for classes?

Here is an example for "properties for classes"

class Foo(object):
    @classmethod
    def get_bar(cls):
        return 'bar'

    @cached_class_property
    def bar(cls):
        return 'bar'

Usage:

assert Foo.bar == Foo.get_bar()

With "cached" I mean that the second (and later) calls to the property returns the value of the first call.

1

There are 1 best solutions below

0
On

Properties are nothing but descriptors, and when we define a descriptor it is always looked up on the type of the object. For instances a descriptor will be looked up on its class and similarly for a class it is going to be looked up on its type, i.e Metaclass.

import random


class cached_class_property(object):
    def __init__(self, func):
        self.func = func
        self.name = '_' + func.__name__

    def __get__(self, obj, type):
        if obj is None:
            return self
        sentinel = object()
        value = getattr(obj, self.name, sentinel)
        if value is sentinel:
            value = self.func(obj)
            setattr(obj, self.name, value)
        return value


class Meta(type):

    @cached_class_property
    def bar(cls):
        value = random.random()
        return value


class Foo(object):
    __metaclass__ = Meta

Demo:

>>> %run so.py
>>> Foo.bar
0.3896508798298206
>>> Foo.bar
0.3896508798298206
>>> Foo.bar
0.3896508798298206
>>> class Bar(Foo):
...     pass
...
>>> Bar.bar
0.3896508798298206
>>> Bar.bar
0.3896508798298206