def cached_property(fnc):
    """Helper decorator for lazy computing properties"""
    name = fnc.__name__

    def get_or_compute(self):
        cache_attr = getattr(self, "_%s" % name, None)
        if cache_attr is not None: return cache_attr
        
        if not hasattr(self, "_cache"): self._cache = {}

        if name not in self._cache:
            self._cache[name] = fnc(self)
        
        return self._cache[name]
    
    return property(get_or_compute)