def cached_property(method):
    """
    :param method: a method without arguments except self
    :returns: a cached property
    """
    name = method.__name__

    def newmethod(self):
        try:
            val = self.__dict__[name]
        except KeyError:
            val = method(self)
            self.__dict__[name] = val
        return val
    newmethod.__name__ = method.__name__
    newmethod.__doc__ = method.__doc__
    return property(newmethod)