Here is a very simple python function that requires no libraries, implements some of the deepest python magic and is still remarkably easy to understand:
def memoize_property(f):
"""A lightweight decorator that combines @property and memoization"""
assert f.__name__
class Memoize(object):
# This class implements the non-data descriptor protocol
# The computed value is memoized to the object instance thus
# overriding the __get__ method on subsequent accesses
def __get__(descriptor,instance,owner):
value = f(instance)
setattr(instance,f.__name__,value)
return value
return Memoize()
It was designed to be used a decorator anywhere you might find yourself creating recursive defintiions:
@memoize_property
def selections(self):
return self.submodel.selections + self.extras
Here I have a recursive definition which would needlessly waste clock cycles if it were implemented using the @property decorator. I really only need to calculate this once and then replace it with the calculated value, much as a spreadsheet would do. (This is the kind of behaviour you would get for free in Haskell — maybe lazy_property or thunk_property would be a better name)
Here’s the same code but removing the class closure which I think clarifies the exposition but is actually unnecessary. The class constructor is in itself the decorator
class memoize_property(object):
"""A lightweight decorator that combines @property and memoization"""
# The class constructor is used directly as a decorator
# This class implements the non-data descriptor protocol
# The computed value is memoized to the object instance thus
# overriding the __get__ method on subsequent accesses
def __init__(descriptor,f):
assert f.__name__
descriptor.f = f
def __get__(descriptor,instance,owner):
value = descriptor.f(instance)
setattr(instance,descriptor.f.__name__,value)
return value