Welp, I discovered descriptors in python. I was trying to implement something similar to @property
, which I thought of as some weird decorator, which turns a function into some sort of a function that is called without the ()
brackets.
Of course an automatically called function is something impossible, but one could inject something into cls.__getattr__
perhaps? Turns out this is also impossible (afaik) - to get to the class one has to either hook into where the function is defined; or have something called to reach self
and then hook into __getattr__
, but we don't have anything being called...
After understanding that I got no clue how to create property
on my own, I googled for that, and now I got this:
class prop: def __init__(self, fget): self.fget = fget def __get__(self, obj, objtype=None): return self.fget(obj) class A: @prop def data(self): return 32
If I produce an object with a method __get__(self, obj, objtype=None)
inside another class, then this object is magically called without any brackets. Yeap, descriptors.
Btw, here is a link for more info: https://docs.python.org/3/howto/descriptor.html#properties
As for what I wanted to do, I now got this:
def lazy(load='scan'): class desc: def __init__(self, prop): self.attr = f'_{prop.__name__}' def __get__(self, obj, objtype = None): if not hasattr(obj, self.attr) or getattr(obj, self.attr) == None: getattr(obj, load)() return getattr(obj, self.attr) return desc class A: def __init__(self): pass @lazy() def data(): pass @lazy() def other(): pass def scan(self): self._data = 42 self._other = 34
Now I can have multiple properties lazily loaded when they are needed. Yeaay.
Top comments (0)