import functools


def lazy_property(func):
    """
    >>> def add(i, j):
    ...     print('add called')
    ...     return i + j
    ...
    >>> class K(object):
    ...
    ...     @lazy_property
    ...     def lazy_number(self):
    ...         return add(1, 1)
    ...
    ...     @property
    ...     def number(self):
    ...         return add(1, 1)
    ...
    >>> k = K()
    >>> k.lazy_number
    add called
    2
    >>> k.lazy_number
    2
    >>> k.number
    add called
    2
    >>> k.number
    add called
    2

    :type func: types.FunctionType
    :rtype: types.FunctionType
    """
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        instance = args[0]
        member_name = '_{}_taskr_lazy_property'.format(func.__name__)
        result = getattr(instance, member_name, None)
        if not result:
            result = func(*args, **kwargs)
            setattr(instance, member_name, result)
        return result
    return property(wrapper)