Add timed_cached_property decorator
[cached-property.git] / cached_property.py
1 # -*- coding: utf-8 -*-
2
3 __author__ = 'Daniel Greenfeld'
4 __email__ = 'pydanny@gmail.com'
5 __version__ = '0.1.4'
6 __license__ = 'BSD'
7
8 import time
9
10
11 class cached_property(object):
12 """ A property that is only computed once per instance and then replaces
13 itself with an ordinary attribute. Deleting the attribute resets the
14 property.
15
16 Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76
17 """
18
19 def __init__(self, func):
20 self.__doc__ = getattr(func, '__doc__')
21 self.func = func
22
23 def __get__(self, obj, cls):
24 if obj is None:
25 return self
26 value = obj.__dict__[self.func.__name__] = self.func(obj)
27 return value
28
29
30 class timed_cached_property(object):
31 '''Decorator for read-only properties evaluated only once within TTL period.
32
33 It can be used to created a cached property like this::
34
35 import random
36
37 # the class containing the property must be a new-style class
38 class MyClass(object):
39 # create property whose value is cached for ten minutes
40 @cached_property(ttl=600)
41 def randint(self):
42 # will only be evaluated every 10 min. at maximum.
43 return random.randint(0, 100)
44
45 The value is cached in the '_cache' attribute of the object instance that
46 has the property getter method wrapped by this decorator. The '_cache'
47 attribute value is a dictionary which has a key for every property of the
48 object which is wrapped by this decorator. Each entry in the cache is
49 created only when the property is accessed for the first time and is a
50 two-element tuple with the last computed property value and the last time
51 it was updated in seconds since the epoch.
52
53 The default time-to-live (TTL) is 0, which also means the cache never expires.
54
55 To expire a cached property value manually just do::
56
57 del instance._cache[<property name>]
58
59 © 2011 Christopher Arndt, MIT License
60 source: https://wiki.python.org/moin/PythonDecoratorLibrary#Cached_Properties
61
62 '''
63 def __init__(self, ttl=0):
64 self.ttl = ttl
65
66 def __call__(self, fget, doc=None):
67 self.fget = fget
68 self.__doc__ = doc or fget.__doc__
69 self.__name__ = fget.__name__
70 self.__module__ = fget.__module__
71 return self
72
73 def __get__(self, inst, owner):
74 now = time.time()
75 try:
76 value, last_update = inst._cache[self.__name__]
77 if self.ttl > 0 and now - last_update > self.ttl:
78 raise AttributeError
79 except (KeyError, AttributeError):
80 value = self.fget(inst)
81 try:
82 cache = inst._cache
83 except AttributeError:
84 cache = inst._cache = {}
85 cache[self.__name__] = (value, now)
86 return value