Lazy attribute loading

How would you implement the lazy load of the attributes of an object, that is, if access to the attributes, but does not yet exist, is some kind of object method called that should 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 only for specific attribute names. Until I did a lot of metaclassing, I'm not sure if this is the right approach. What would you suggest?

+5
source share
1 answer

Simple seems propertyto do the trick better:

@property
def my_attribute():
    if not hasattr(self, '_my_attribute'):
        do_expensive_operation_to_get_attribute()
    return self._my_attribute
+6
source

All Articles