python lazy variables? or, delayed expensive computation

The first half of your problem (reusing the value) is easily solved:

class LazyWrapper(object):
    def __init__(self, func):
        self.func = func
        self.value = None
    def __call__(self):
        if self.value is None:
            self.value = self.func()
        return self.value

lazy_wrapper = LazyWrapper(lambda: function_that_generates_huge_array_slowly(0))

But you still have to use it as lazy_wrapper() not lazy_wrapper.

If you're going to be accessing some of the variables many times, it may be faster to use:

class LazyWrapper(object):
    def __init__(self, func):
        self.func = func
    def __call__(self):
        try:
            return self.value
        except AttributeError:
            self.value = self.func()
            return self.value

Which will make the first call slower and subsequent uses faster.

Edit: I see you found a similar solution that requires you to use attributes on a class. Either way requires you rewrite every lazy variable access, so just pick whichever you like.

Edit 2: You can also do:

class YourClass(object)
    def __init__(self, func):
        self.func = func
    @property
    def x(self):
        try:
            return self.value
        except AttributeError:
            self.value = self.func()
            return self.value

If you want to access x as an instance attribute. No additional class is needed. If you don't want to change the class signature (by making it require func), you can hard code the function call into the property.


Writing a class is more robust, but optimizing for simplicity (which I think you are asking for), I came up with the following solution:

cache = {}

def expensive_calc(factor):
    print 'calculating...'
    return [1, 2, 3] * factor

def lookup(name):
    return ( cache[name] if name in cache
        else cache.setdefault(name, expensive_calc(2)) )

print 'run one'
print lookup('x') * 2

print 'run two'
print lookup('x') * 2

Tags:

Python

Numpy