def cached_property(fn):
    """
    Converts a class's method into property and cache's the getter value.

    Simple decorator a method with this function and it will be converted into
    a property (attribute access) and the calculation to retrieve the value
    will be cached so that the initial call performs the calculation, but
    subsequent calls will use the cache.
    """
    attr_name = '_' + fn.__name__

    def _wrapper(self):
        value = getattr(self, attr_name, None)
        if value is None:
            value = fn(self)
            setattr(self, attr_name, value)

        return value

    _wrapper.__name__ = fn.__name__
    _wrapper.__doc__ = fn.__doc__

    return property(_wrapper)