“Lazy” property that gets initialized automatically at __init__
我想使用一些类似于通常的惰性属性修饰器的东西,但是由于TensorFlow是如何工作的以及如何使用它,我需要在最新的
以下工作已经开始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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) |
不过,最好不要在
我在考虑多种方法来"记住"哪些属性是
我可以想象的一种工作方式是给返回的
所述方法是否可行(如果可行,如何实现)?或者有一个更简单的方法(没有手动开销,语法也同样好)而我只是没有看到它?
您可以添加一个简单的mixin并定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | import functools class lazy_property(property): """ This class will help us in identifying our lazy properties, so that we don't confuse them with normal properties. """ pass def graph_property(getter): property_name = getter.__name__ attribute = '_cache_' + property_name @lazy_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 InitializeLazyPropertiesMixin: """ This mixin does all of the work of initializing lazy properties """ def __init__(self): cls = type(self) fields = (k for k in dir(cls) if isinstance(getattr(cls, k), lazy_property)) for field in fields: getattr(self, field) class Test(InitializeLazyPropertiesMixin): def __init__(self): self._graph = [] # Whenever you're inheriting from this mixin make sure to call # super `__init__` method. super().__init__() @graph_property def inputs(self): return 42.0 @graph_property def do_stuff(self): return self.inputs + 1.0 class Test1: """ Just another class that doesn't require initializing any of the lazy properties """ def __init__(self): self._graph = [] @graph_property def inputs(self): return 42.0 @graph_property def do_stuff(self): return self.inputs + 1.0 |
演示输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> t = Test() Initializing inputs Initializing do_stuff >>> print(t._graph) ['inputs', 'do_stuff'] >>> t = Test1() >>> print(t._graph) [] >>> t.inputs Initializing inputs 42.0 >>> t._graph ['inputs'] |
。
由于您可以完全控制属性和类层次结构,因此只需标记要初始化的属性,并在将调用所有属性的基类
因此,首先,在您的decorator中,在您的图形属性decorator上设置一个变量,以便它标记要初始化的方法。由于与函数不同,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class MarcableProperty(property): pass def graph_property(getter): property_name = getter.__name__ attribute = '_cache_' + property_name @MarcableProperty @functools.wraps(getter) def decorated(self): ... decorated._graph_initialize = True return decorated |
然后,在所有其他类的基础类或混合类上,执行以下操作:
1 2 3 4 5 6 7 8 9 | def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for cls_member_name in dir(self.__class__): #"dir" is good because it automatically looks # at the superclasses as well cls_member = getattr(self.__class__, cls_member_name) if getattr(cls_member,"_graph_initialize", False): # Fetch property, initializing its value: getattr(self, cls_member_name) |
号
就这样吧。