I am trying to access an attribute that shouldn\'t be created in the __init__
method of my class but can be calculated by calling another method. I am trying to
Pyramid (a Web framework) comes with a reify
decorator that is similar to property
(shown by Austin Hastings) but it works a little differently: the function is only executed once, and after that, the value returned by the function is always used. It essentially does what Austin's code does, but without having to use a separate attribute: it's a generalization of that pattern.
You probably don't want to use a whole Web framework just for this one decorator, so here is an equivalent one I wrote:
import functools
class Descriptor(object):
def __init__(self, func):
self.func = func
def __get__(self, inst, type=None):
val = self.func(inst)
setattr(inst, self.func.__name__, val)
return val
def reify(func):
return functools.wraps(func)(Descriptor(func))
Usage:
class ReifyDemo:
@reify
def total(self):
"""Compute or return the total attribute."""
print("calculated total")
return 2 + 2 # some complicated calculation here
r = ReifyDemo()
print(r.total) # prints 'calculated total 4' because the function was called
print(r.total) # prints just '4` because the function did not need to be called
You want to use the @property
decorator. Create a method, that will be accessed like a normal attribute, that does lazy computation:
class SampleObject:
def __init__(self):
# ...
self._total = None
@property
def total(self):
"""Compute or return the _total attribute."""
if self._total is None:
self.compute_total()
return self._total