public

A CachedProperty descriptor; It receives an expensive getter function (& optional arguments for it). The __get__ runs the getter function with the object instance as the first argument (& optional arguments provided in __init__) and caches the result. The __set__ just changes the cache to the 'value', __delete__ removes the cache.

  • Download Gist
cached_property_descriptor.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
class CachedProperty(object):
"""
A cached property; A bit specific, as
it runs the getter as an instance method
& forwards the instance & init args to it.
Uses python descriptors protocol
"""
def __init__(self, getter, *args):
self.getter = getter
self.args = args or None
 
def __get__(self, instance, owner):
# If we don't have cache, go ahead and call the getter & cache its result
if not hasattr(self, '_cache'):
# This is the expensive getter call; The getter is provided with instance & optional args
result = self.getter(instance, *self.args) if self.args is not None else self.getter(instance)
# Cache the result in self
setattr(self, '_cache', result)
# We always return our cache
return getattr(self, '_cache')
 
def __set__(self, instance, value):
# Set the new value to the cache
setattr(self, '_cache', value)
 
def __delete__(self, instance):
# Remove cache
delattr(self, '_cache')
 
 
# USAGE
 
class SomeClass(object):
A, B, C = 1, 2, 3
def __init__(self, *args, **kwargs):
self.args = args or ()
self.kwargs = kwargs or {}
def has_arg(self, arg):
return arg in self.args
def expensive_getter_fn(x)
# An expensive computation here
return x
# Typical usage case: expensive getter & some args for it to receive
my_cached_prop_a = CachedProperty(expensive_getter_fn, SomeClass.A)
my_cached_prop_b = CachedProperty(expensive_getter_fn, SomeClass.B)
my_cached_prop_c = CachedProperty(expensive_getter_fn, SomeClass.C)
# Another way to use it: lambda getter that invokes some instance method
my_cached_prop_d = CachedProperty(lambda instance, arg: instance.has_arg, "some_arg")

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.