Created
September 6, 2013 10:13
-
-
Save aleksandarristic/6461998 to your computer and use it in GitHub Desktop.
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment