Replace implementation of 'cached_property'
Parameter 'ttl' isn't needed.pull/21/head
parent
e3b6ee2fd6
commit
cc00976533
@ -1,61 +1,23 @@
|
||||
import time
|
||||
# -*- coding: utf8 -*-
|
||||
|
||||
|
||||
#
|
||||
# ? 2011 Christopher Arndt, MIT License
|
||||
#
|
||||
class cached_property(object):
|
||||
'''Decorator for read-only properties evaluated only once within TTL
|
||||
period.
|
||||
def cached_property(getter):
|
||||
"""
|
||||
Decorator that converts a method into memoized property.
|
||||
The decorator will work as expected only for immutable properties.
|
||||
"""
|
||||
def decorator(self):
|
||||
if not hasattr(self, "__cached_property_data"):
|
||||
self.__cached_property_data = {}
|
||||
|
||||
It can be used to created a cached property like this::
|
||||
key = getter.__name__
|
||||
if key not in self.__cached_property_data:
|
||||
self.__cached_property_data[key] = getter(self)
|
||||
|
||||
import random
|
||||
return self.__cached_property_data[key]
|
||||
|
||||
# the class containing the property must be a new-style class
|
||||
class MyClass(object):
|
||||
# create property whose value is cached for ten minutes
|
||||
@cached_property(ttl=600) def randint(self):
|
||||
# will only be evaluated every 10 min. at maximum.
|
||||
return random.randint(0, 100)
|
||||
decorator.__name__ = getter.__name__
|
||||
decorator.__module__ = getter.__module__
|
||||
decorator.__doc__ = getter.__doc__
|
||||
|
||||
The value is cached in the '_cache' attribute of the object instance that
|
||||
has the property getter method wrapped by this decorator. The '_cache'
|
||||
attribute value is a dictionary which has a key for every property of the
|
||||
object which is wrapped by this decorator. Each entry in the cache is
|
||||
created only when the property is accessed for the first time and is a
|
||||
two-element tuple with the last computed property value and the last time
|
||||
it was updated in seconds since the epoch.
|
||||
|
||||
The default time-to-live (TTL) is 300 seconds (5 minutes). Set the TTL to
|
||||
zero for the cached value to never expire.
|
||||
|
||||
To expire a cached property value manually just do::
|
||||
|
||||
del instance._cache[<property name>]
|
||||
|
||||
'''
|
||||
def __init__(self, ttl=300):
|
||||
self.ttl = ttl
|
||||
|
||||
def __call__(self, fget, doc=None):
|
||||
self.fget = fget
|
||||
self.__doc__ = doc or fget.__doc__
|
||||
self.__name__ = fget.__name__
|
||||
self.__module__ = fget.__module__
|
||||
return self
|
||||
|
||||
def __get__(self, inst, owner):
|
||||
now = time.time()
|
||||
try:
|
||||
value, last_update = inst._cache[self.__name__]
|
||||
if self.ttl > 0 and now - last_update > self.ttl:
|
||||
raise AttributeError
|
||||
except (KeyError, AttributeError):
|
||||
value = self.fget(inst)
|
||||
try:
|
||||
cache = inst._cache
|
||||
except AttributeError:
|
||||
cache = inst._cache = {}
|
||||
cache[self.__name__] = (value, now)
|
||||
return value
|
||||
return property(decorator)
|
||||
|
Loading…
Reference in New Issue