1

In my code I want to create a bunch of lazy variables, however, if any one of them is being queried, the Load() function as a whole should be called, which will populate all the underlying lazy variables at once.

Currently my class looks like this:

@property
def test1(self):
    if (not self.__test1):
        self.Load()
    return self.__test1

@property
def test2(self):
    if (not self.__test2):
        self.Load()
    return self.__test2

....

Since this looks quite ugly if being done on 30+ variables, I was wondering if there is a way to do this prettier in Python, maybe with some smart decorator?

Thank you for your replies

4
  • Is Load really the method called for all of them? If Load returns the same thing each time, it's not clear why you have multiple properties. If it returns a different value, then it seems like each property is cache for what is otherwise a sequence of calls to the same property. Commented Aug 6, 2015 at 16:30
  • The answer is probably "it can be done", but I'm not quite sure how it'd be done off the top of my head. (Metaclass? Class decorator? Descriptors? Implementing a very odd __getattr__?) Commented Aug 6, 2015 at 16:37
  • Does self.Load() set the values of __test1 et al? Otherwise, how do they get set? Commented Aug 6, 2015 at 16:45
  • self.Load() returns nothing. Instead it sets all values of the variables at once (it's basically a cPickle.load() operation where it's unfeasible to load the individual parts, and much more efficient to load everything at once). Commented Aug 6, 2015 at 17:02

1 Answer 1

1

You can define a metaclass to dynamically create all the properties that needs lazy loading. This metaclass gets the property names from a list lazy_props defined in your own class, and within __new__() generate the properties in your class.

The code is like this:

class LazyMeta(type):
    def __new__(cls, clsname, bases, clsdict):
        d = dict(clsdict)
        props = d.get("lazy_props")
        def lazy_load(_attr):
            def wrapped_method(self):
                variable = "_" + _attr
                if not hasattr(self, variable):
                    self.Load()
                return getattr(self, variable)
            return wrapped_method

        for prop in props:
            _method = lazy_load(prop)
            _property = property(_method)
            d[prop] = _property

        return type.__new__(cls, clsname, bases, d)

# Your class uses LazyMeta as metaclass
class LazyClass:
    __metaclass__ = LazyMeta
    lazy_props = ['test1', 'test2']
    def Load(self):
        print "Loading ..."
        self._test1=123
        self._test2=456

Now when you instantiate a object of LazyClass:

>>> l = LazyClass()
>>> l.test1
Loading ...
123
>>> l.test2
456

Note I used _test1, _test2 in place of __test1, __test2, because python treat variables starting with double underscore specially, and it prevents getattr() from working properly.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.