Python way to only do the job the first time the variable is called

my Python class has some variables that require work to compute on the first call. Subsequent calls should simply return the previously computed value.

I do not want to waste time doing this work if the user really does not need them. So, is there a pure Pythonic way to implement this use case?

My initial thought was to use property () to call the function for the first time, and then override the variable:

class myclass(object): def get_age(self): self.age = 21 # raise an AttributeError here return self.age age = property(get_age) 

thanks

+6
variables python class precompute
source share
4 answers
 class myclass(object): def __init__(self): self.__age=None @property def age(self): if self.__age is None: self.__age=21 #This can be a long computation return self.__age 

Alex mentioned that you can use __getattr__ , this is how it works

 class myclass(object): def __getattr__(self, attr): if attr=="age": self.age=21 #This can be a long computation return super(myclass, self).__getattribute__(attr) 

__getattr__() is called when the attribute does not exist on the object, i.e. at the first attempt to access age . Each time after this age exists, therefore __getattr__ does not receive a call

+13
source share

property , as you saw, will not allow you to override it. You need to use a slightly different approach, for example:

 class myclass(object): @property def age(self): if not hasattr(self, '_age'): self._age = self._big_long_computation() return self._age 

There are other approaches, such as __getattr__ or a custom descriptor class, but it's easier! -)

+6
source share

Here's a decorator from the Python Cookbook for this problem:

 class CachedAttribute(object): ''' Computes attribute value and caches it in the instance. ''' def __init__(self, method, name=None): # record the unbound-method and the name self.method = method self.name = name or method.__name__ def __get__(self, inst, cls): if inst is None: # instance attribute accessed on class, return self return self # compute, cache and return the instance attribute value result = self.method(inst) setattr(inst, self.name, result) return result 
+4
source share

Yes, you can use properties, although lazy evaluation is also often done using descriptors, see for example:

http://blog.pythonisito.com/2008/08/lazy-descriptors.html

+2
source share

All Articles