I want to use something like the usual lazy property decorator, but due to how TensorFlow works and how I use it, I need all of the lazy properties to be initialized automatically at __init__
the latest (the TensorFlow part is not part of the question, but see here for what I mean). By "initializing" I just mean calling getattr
to run the property method once and cache the result.
The following works already:
import functools
def graph_property(getter):
property_name = getter.__name__
attribute = '_cache_' + property_name
@property
@functools.wraps(getter)
def decorated(self):
if not hasattr(self, attribute):
setattr(self, attribute, getter(self))
self._graph.append(property_name) # for illustration
print('Initializing ' + property_name)
return getattr(self, attribute)
return decorated
class Test:
def __init__(self):
self._graph = []
self.inputs # DON'T LIKE TO DO THIS
self.do_stuff # AND THIS
@graph_property
def inputs(self):
return 42.0
@graph_property
def do_stuff(self):
return self.inputs + 1.0
if __name__ == '__main__':
t = Test()
print(t._graph)
However, it would be nice to get rid of the manual calls to self.input
and self.do_stuff
in __init__
-- that quickly gets tedious.
I was thinking about multiple ways of "remembering" which properties are graph_property
s somewhere in a list, but all must fail, I think, since at the time the decorator is applied, the class is not yet known to it (let alone self
).
One way I could imagine to work is giving the returned decorated
object some tag attribute, and write a metaclass for Test
which looks at all methods, collects the ones with this tag, and somehow creates an initializer for them. I failed to implement this because I'm very not familiar with metaclasses and the property
descriptor doesn't let me add attributes.
Would the described approach be feasible (if so, how)? Or is there an easier way (without manual overhead and with equally nice syntax) and I'm just not seeing it?