import six


def cached_property(cache_key):
    """
    Decorator to cache the return value of an instance property.

    .. code-block:: python

        class MyClass(object):

            @cached_property('_cached_property'):
            def cached_property(self):
                return ...

        # usage
        o = MyClass()
        print(o.cached_property)  # fetch the cached value

    Args:
        cache_key (str): Attribute name to store the cached value.
    """
    def wrapper(method):
        @property
        @six.wraps(method)
        def inner(self, *args, **kwargs):
            if not hasattr(self, cache_key):
                setattr(self, cache_key, method(self, *args, **kwargs))
            return getattr(self, cache_key)
        return inner

    return wrapper