A simple python decorator

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