2

Well in C++ the aformented idom (construct on first use) is quite common. I however like to make it also in python, together with references/pointers that often accompany this. Just a quick example (half pseudo code):

class data:
    def __init__(self, file):
        self.raw_data = read_file() 
        #takes upto 1 minute and should only be done if necessary.
        self.temperature = temp_conv() #again takes a lot of time

class interface:
    def __init__(self, plot, data, display_what):
        self.dat = data
        self.disp = display_what
        self.current_time = 0
        #...
    def display():
        #display the correct data (raw_data) or temperature
        #mainly creating a matplotlib interface
        self.img = self.axes.imshow(self.displ[:,:,self.current_time],interpolation='none')
        #what to display actually can be changed through callbacks
    def example_callback():
        self.disp = self.dat.temperature
        self.img.set_data(self.displ[:,:,self.current_time])

dat = data("camera.dat")
disp = interface(dat, raw_data)
disp.display()

Now the first approach is to simply create everything at start, but this takes several minutes in total. And probably more in the future.

So now I wish to make it so that I only "calculate" what is needed the moment I actually get the reference. So not at construction of the data object.

Now I could do this at the callback functions, test there if data has already calculated the correct function and if not calculate it. But this feels very annoying and not good programming ettiquette (the interface suddenly is responsible for checking & creating data).

So I'd like to have the data class to contain itself. Remove the self.temperature = temp_conv() and replace it with a structure that puts it initially at None but when you try to read it for the first time it executes the temp_conv() script.

paul23
  • 8,799
  • 12
  • 66
  • 149
  • So you want to make the attributes into [`@property`](http://stackoverflow.com/q/6618002/3001761)s? – jonrsharpe Mar 18 '15 at 16:30
  • What you describe can be done with properties. See [this blog post](http://stevenloria.com/lazy-evaluated-properties-in-python/) and [this question](http://stackoverflow.com/questions/3012421/python-lazy-property-decorator). – BrenBarn Mar 18 '15 at 16:31

1 Answers1

2

It's a simple as providing a property instead of the attribute, which will then evaluate the code only on demand

A very simple variant is this:

 import time


 class Deferred(object):

     def __init__(self, initializer):
         self._initializer = initializer
         self._value = None
         self._initialized = False


     def __call__(self):
         if not self._initialized:
             self._value = self._initializer()
             self._initialized = True
         return self._value


 class Foo(object):

     def __init__(self):
         self._lazy_data = Deferred(lambda: time.sleep(1.0))


     @property
     def lazy_data(self):
         return self._lazy_data()


 f = Foo()
 print "a"
 f.lazy_data
 print "b"
 f.lazy_data
 print "c"
deets
  • 6,285
  • 29
  • 28
  • If I'm correct at initialization you set the variable to a lambda function. Then at "get" you check if it is a function (callable) and if, execute it and put the result back in the variable (now no longer a function).. Coming from a C++ & JAVA background type changes like that irk me like no tomorrow. But it is a good example that shows the working and I can modify it to my preferences/needs. Testing now. – paul23 Mar 18 '15 at 16:41
  • Well, if in rome, do as the romans do. There are other ways to accomplish this though, as the protocol (as I stated) isn't really ideal as it relies on the value *not* being a callable. A different approach could utilize a small utility-class. I update my answer accordingly. – deets Mar 18 '15 at 16:48