Why doesn't the value of `monopoly.boardwalk` change? Because it's a **cached property**!
-What if I want to use a cache that times out?
--------------------------------------------------
-
-Just import the `timed_cached_property`:
-
-.. code-block:: python
-
- from cached_property import timed_cached_property
-
- class Monopoly(object):
-
- def __init__(self):
- self.boardwalk_price = 500
-
- # Times out in 5 minutes
- @timed_cached_property(ttl=300)
- def boardwalk(self):
- # Sometimes the market crashes and prices drop back down to their
- # original value.
- self.boardwalk_price += 50
- return self.boardwalk_price
-
Credits
--------
return self
value = obj.__dict__[self.func.__name__] = self.func(obj)
return value
-
-
-class timed_cached_property(object):
- '''Decorator for read-only properties evaluated only once within TTL period.
-
- It can be used to created a cached property like this::
-
- import random
-
- # 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)
-
- 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 0, which also means the cache never expires.
-
- To expire a cached property value manually just do::
-
- del instance._cache[<property name>]
-
- © 2011 Christopher Arndt, MIT License
- source: https://wiki.python.org/moin/PythonDecoratorLibrary#Cached_Properties
-
- '''
- def __init__(self, ttl=0):
- 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
import unittest
-from cached_property import cached_property, timed_cached_property
+from cached_property import cached_property
class TestCachedProperty(unittest.TestCase):
# The cached version demonstrates how nothing new is added
self.assertEqual(c.add_cached, 1)
- self.assertEqual(c.add_cached, 1)
-
-
-class TestTimedCachedProperty(unittest.TestCase):
-
- def test_normal_cached_property(self):
-
- class Check(object):
-
- def __init__(self):
- self.total1 = 0
- self.total2 = 0
-
- @property
- def add_control(self):
- self.total1 += 1
- return self.total1
-
- @timed_cached_property(ttl=1)
- def add_cached(self):
- self.total2 += 1
- return self.total2
-
- c = Check()
-
- # The control shows that we can continue to add 1.
- self.assertEqual(c.add_control, 1)
- self.assertEqual(c.add_control, 2)
-
- # The cached version demonstrates how nothing new is added
- self.assertEqual(c.add_cached, 1)
- self.assertEqual(c.add_cached, 1)
-
-if __name__ == '__main__':
- unittest.main()
+ self.assertEqual(c.add_cached, 1)
\ No newline at end of file