Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy loading of attributes

Tags:

python

How would you implement lazy load of object attributes, i.e. if attributes are accessed but don't exist yet, some object method is called which is supposed to load these?

My first attempt is

def lazyload(cls):
    def _getattr(obj, attr):
        if "_loaded" not in obj.__dict__:
            obj._loaded=True
            try:
                obj.load()
            except Exception as e:
                raise Exception("Load method failed when trying to access attribute '{}' of object\n{}".format(attr, e))
            if attr not in obj.__dict__:
                AttributeError("No attribute '{}' in '{}' (after loading)".format(attr, type(obj))) # TODO: infinite recursion if obj fails
            return getattr(obj, attr)
        else:
            raise AttributeError("No attribute '{}' in '{}' (already loaded)".format(attr, type(obj)))

    cls.__getattr__=_getattr
    return cls

@lazyload
class Test:
    def load(self):
         self.x=1

t=Test()     # not loaded yet
print(t.x)   # will load as x isnt known yet

I will make lazyload specific to certain attribute names only. As I havent done much meta-classing yet, I'm not sure if that is the right approach. What would you suggest?

like image 802
Gerenuk Avatar asked Feb 14 '12 10:02

Gerenuk


1 Answers

Seems like a simple property would do the trick better:

@property
def my_attribute():
    if not hasattr(self, '_my_attribute'):
        do_expensive_operation_to_get_attribute()
    return self._my_attribute
like image 191
Daniel Roseman Avatar answered Oct 06 '22 04:10

Daniel Roseman