How to create decorator for lazy initialization of a property

2024/10/1 23:31:33

I want to create a decorator that works like a property, only it calls the decorated function only once, and on subsequent calls always return the result of the first call. An example:

def SomeClass(object):@LazilyInitializedPropertydef foo(self):print "Now initializing"return 5>>> x = SomeClass()
>>> x.foo
Now initializing
5
>>> x.foo
5

My idea was to write a custom decorator for this. So i started, and this is how far I came:

class LazilyInitializedProperty(object):def __init__(self, function):self._function = functiondef __set__(self, obj, value):raise AttributeError("This property is read-only")def __get__(self, obj, type):# problem: where to store the value once we have calculated it?

As you can see, I do not know where to store the cached value. The simplest solution seems to be to just maintain a dictionary, but I am wondering if there is a more elegant solution for this.

EDIT Sorry for that, I forgot to mention that I want the property to be read-only.

Answer

Denis Otkidach's CachedAttribute is a method decorator which makes attributes lazy (computed once, accessible many). To make it also read-only, I added a __set__ method. To retain the ability to recalculate (see below) I added a __delete__ method:

class ReadOnlyCachedAttribute(object):    '''Computes attribute value and caches it in the instance.Source: Python Cookbook Author: Denis Otkidach https://stackoverflow.com/users/168352/denis-otkidachThis decorator allows you to create a property which can be computed once andaccessed many times. Sort of like memoization'''def __init__(self, method, name=None):self.method = methodself.name = name or method.__name__self.__doc__ = method.__doc__def __get__(self, inst, cls): if inst is None:return selfelif self.name in inst.__dict__:return inst.__dict__[self.name]else:result = self.method(inst)inst.__dict__[self.name]=resultreturn result    def __set__(self, inst, value):raise AttributeError("This property is read-only")def __delete__(self,inst):del inst.__dict__[self.name]

For example:

if __name__=='__main__':class Foo(object):@ReadOnlyCachedAttribute# @read_only_lazypropdef bar(self):print 'Calculating self.bar'  return 42foo=Foo()print(foo.bar)# Calculating self.bar# 42print(foo.bar)    # 42try:foo.bar=1except AttributeError as err:print(err)# This property is read-onlydel(foo.bar)print(foo.bar)# Calculating self.bar# 42

One of the beautiful things about CachedAttribute (and ReadOnlyCachedAttribute) is that if you del foo.bar, then the next time you access foo.bar, the value is re-calculated. (This magic is made possible by the fact that del foo.bar removes 'bar' from foo.__dict__ but the property bar remains in Foo.__dict__.)

If you don't need or don't want this ability to recalculate, then the following (based on Mike Boers' lazyprop) is a simpler way to make a read-only lazy property.

def read_only_lazyprop(fn):attr_name = '_lazy_' + fn.__name__@propertydef _lazyprop(self):if not hasattr(self, attr_name):setattr(self, attr_name, fn(self))return getattr(self, attr_name)@_lazyprop.setterdef _lazyprop(self,value):raise AttributeError("This property is read-only")return _lazyprop
https://en.xdnf.cn/q/70913.html

Related Q&A

How to convert a 24-bit wav file to 16 or 32 bit files in python3

I am trying to make spectrograms of a bunch of .wav files so I can further analyze them(in python 3.6), however, I keep getting this nasty errorValueError: Unsupported bit depth: the wav file has 24-bi…

Get consistent Key error: \n [duplicate]

This question already has answers here:How do I escape curly-brace ({}) characters in a string while using .format (or an f-string)?(23 answers)Closed 8 years ago.When trying to run a script containin…

Cannot take the length of Shape with unknown rank

I have a neural network, from a tf.data data generator and a tf.keras model, as follows (a simplified version-because it would be too long):dataset = ...A tf.data.Dataset object that with the next_x me…

Pre-fill new functions in Eclipse and Pydev with docstring and Not Implemented exception

I am editing my Python source code with Eclipse and Pydev.I want to document all of my functions and raise a "Not Implemented" exception whenever a function have not yet been implemented. For…

How to serialize hierarchical relationship in Django REST

I have a Django model that is hierarchical using django-mptt, which looks like:class UOMCategory(MPTTModel, BaseModel):"""This represents categories of different unit of measurements.&qu…

Django: Loading another template on click of a button

Ive been working on a django project for a few weeks now, just playing around so that I can get the hang of it. I am a little bit confused. I have a template now called "home.html". I was wo…

Given two python lists of same length. How to return the best matches of similar values?

Given are two python lists with strings in them (names of persons):list_1 = [J. Payne, George Bush, Billy Idol, M Stuart, Luc van den Bergen] list_2 = [John Payne, George W. Bush, Billy Idol, M. Stuart…

Extracting Javascript gettext messages using Babel CLI extractor

It is stated here that Babel can extract gettext messages for Python and Javascript files.Babel comes with a few builtin extractors: python (which extractsmessages from Python source files), javascript…

Getting TTFB (time till first byte) for an HTTP Request

Here is a python script that loads a url and captures response time:import urllib2 import timeopener = urllib2.build_opener() request = urllib2.Request(http://example.com)start = time.time() resp = ope…

accessing kubernetes python api through a pod

so I need to connect to the python kubernetes client through a pod. Ive been trying to use config.load_incluster_config(), basically following the example from here. However its throwing these errors. …