Я хочу использовать что-то вроде обычного декоратора lazy property, но из-за того, как работает TensorFlow и как я его использую, мне нужно, чтобы все ленивые свойства были инициализированы автоматически на __init__
последний (часть TensorFlow не является частью вопроса, но см. here, что я имею в виду). Под «инициализацией» я имею в виду вызов getattr
для запуска метода свойства один раз и кэширования результата.Свойство «Lazy», которое автоматически инициализируется на __init__
следующие работы: уже
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)
Однако, было бы неплохо избавиться от ручных вызовов self.input
и self.do_stuff
в __init__
- это быстро становится утомительным.
Я думал о нескольких путях «запоминания», которые являются объектами graph_property
где-то в списке, но все, как мне кажется, все должно потерпеть неудачу, поскольку в то время, когда применяется декоратор, класс еще не известен ему (не говоря уже о self
).
Один из способов я мог себе представить, чтобы работать дает Возвращаемый объект decorated
некоторый атрибут тега, и написать метакласса для Test
, который смотрит на все методы, собирает из них с этим тегом, и каким-то образом создает инициализатор для них. Я не смог реализовать это, потому что я очень не знаком с метаклассами, а дескриптор property
не позволяет добавлять атрибуты.
Будет ли описанный подход осуществимым (если да, каким образом)? Или есть более простой способ (без ручных накладных расходов и с одинаково приятным синтаксисом), и я просто не вижу его?
Ах, этот подклассический трюк красив! У меня есть общий базовый класс, так что это идеально подходит. – phg
Мне просто пришло в голову, что 'vars (type (self)). Items()' не будет включать переменные, определенные в суперклассах, - это просто проверяет дескрипторы на объявленном классе, а не на его предках. – jsbueno
@jsbueno Хороший улов, обновленный для использования 'dir()', который [рекурсивно решается] (http://stackoverflow.com/a/33089239/846892), чтобы получить атрибуты. –