@cached_property is an amazing way to simplify your code. It's like the regular
@property but remembers the value after the first call:
class C: @cached_property def p(self): print('computing...') return 1 c = C() c.p # computing... # 1 c.p # 1
The implementation is short and relatively simple:
class cached_property: def __init__(self, func): self.func = func def __get__(self, obj, cls): if obj is None: return self value = obj.__dict__[self.func.__name__] = self.func(obj) return value
However, there are a few corner-cases, like async functions and threads. Luckily, from Python 3.8 it's a part of standard library (functools.cached_property) and for older versions cached-propery library can be used.