Существует множество примеров декораторов методов, которые преобразуют метод в кэшированное свойство. Однако иногда я хотел бы проверить, является ли кэш «активным», что означает, что к атрибуту обращались и кэш был заполнен.
Например, если я использую кэшированный rows
для хранения таблицы sql в rows
, я бы хотел вычислить длину моей таблицы на основе кэша, если он заполнен, но через отдельный sql вызов, если нет. Как мне проверить, был ли получен доступ к rows
, не вызывая его доступа?
Вот хороший декоратор, взятый из "Python Cookbook" Дэвида Бизли), который я использую для своих потребностей в кэшированных свойствах. Я улучшил его, чтобы включить мой текущий взлом.
class lazyprop:
def __init__(self, func):
self.func = func
def __get__(self, instance, cls):
if instance is None:
return self
else:
value = self.func(instance)
setattr(instance, self.func.__name__, value)
setattr(instance, self.func.__name__ + '__cache_active', True) # my hack
return value
Пример использования:
>>> class Test:
... def __init__(self, a):
... self.a = a
... @lazyprop
... def len(self):
... print('generating "len"')
... return len(self.a)
>>> t = Test([0, 1, 2])
>>> # See what happens if I ask if there is a 'len' attribute:
>>> hasattr(t, 'len')
generating "len"
3
>>> t.len
5
Так что hasattr
фактически вызывает вызов метода len
, поэтому я могу Не используйте это. В любом случае, я не хотел бы использовать его, потому что я не спрашиваю о существовании атрибута (ключ / ссылка), но о существовании (то есть до вычисления) его значения.
Учитывая строку, помеченную «моим хаком», теперь я могу сделать следующее:
def has_active_cache(instance, attr):
return getattr(instance, attr + '__cache_active', False)
>>> t = Test([0, 1, 2])
>>> print("Accessed:", has_active_cache(t, 'len'))
Accessed: False
>>> t.len
generating "len"
3
>>> print("Accessed:", has_active_cache(t, 'len'))
Accessed: True
Но я считаю, что есть более изящное решение, чем это. Возможно, тот, который будет «связан» с самим lazyprop
...