OLD | NEW |
(Empty) | |
| 1 """`functools.lru_cache` compatible memoizing function decorators.""" |
| 2 |
| 3 import collections |
| 4 import functools |
| 5 import random |
| 6 import time |
| 7 import warnings |
| 8 |
| 9 try: |
| 10 from threading import RLock |
| 11 except ImportError: |
| 12 from dummy_threading import RLock |
| 13 |
| 14 from .keys import hashkey, typedkey |
| 15 |
| 16 __all__ = ('lfu_cache', 'lru_cache', 'rr_cache', 'ttl_cache') |
| 17 |
| 18 |
| 19 class _NLock: |
| 20 def __enter__(self): |
| 21 pass |
| 22 |
| 23 def __exit__(self, *exc): |
| 24 pass |
| 25 |
| 26 _CacheInfo = collections.namedtuple('CacheInfo', [ |
| 27 'hits', 'misses', 'maxsize', 'currsize' |
| 28 ]) |
| 29 |
| 30 _marker = object() |
| 31 |
| 32 |
| 33 def _deprecated(message, level=2): |
| 34 warnings.warn('%s is deprecated' % message, DeprecationWarning, level) |
| 35 |
| 36 |
| 37 def _cache(cache, typed=False, context=_marker): |
| 38 def decorator(func): |
| 39 key = typedkey if typed else hashkey |
| 40 if context is _marker: |
| 41 lock = RLock() |
| 42 elif context is None: |
| 43 lock = _NLock() |
| 44 else: |
| 45 lock = context() |
| 46 stats = [0, 0] |
| 47 |
| 48 def cache_info(): |
| 49 with lock: |
| 50 hits, misses = stats |
| 51 maxsize = cache.maxsize |
| 52 currsize = cache.currsize |
| 53 return _CacheInfo(hits, misses, maxsize, currsize) |
| 54 |
| 55 def cache_clear(): |
| 56 with lock: |
| 57 try: |
| 58 cache.clear() |
| 59 finally: |
| 60 stats[:] = [0, 0] |
| 61 |
| 62 def wrapper(*args, **kwargs): |
| 63 k = key(*args, **kwargs) |
| 64 with lock: |
| 65 try: |
| 66 v = cache[k] |
| 67 stats[0] += 1 |
| 68 return v |
| 69 except KeyError: |
| 70 stats[1] += 1 |
| 71 v = func(*args, **kwargs) |
| 72 try: |
| 73 with lock: |
| 74 cache[k] = v |
| 75 except ValueError: |
| 76 pass # value too large |
| 77 return v |
| 78 functools.update_wrapper(wrapper, func) |
| 79 if not hasattr(wrapper, '__wrapped__'): |
| 80 wrapper.__wrapped__ = func # Python < 3.2 |
| 81 wrapper.cache_info = cache_info |
| 82 wrapper.cache_clear = cache_clear |
| 83 return wrapper |
| 84 return decorator |
| 85 |
| 86 |
| 87 def lfu_cache(maxsize=128, typed=False, getsizeof=None, lock=_marker): |
| 88 """Decorator to wrap a function with a memoizing callable that saves |
| 89 up to `maxsize` results based on a Least Frequently Used (LFU) |
| 90 algorithm. |
| 91 |
| 92 """ |
| 93 from .lfu import LFUCache |
| 94 if lock is not _marker: |
| 95 _deprecated("Passing 'lock' to lfu_cache()", 3) |
| 96 return _cache(LFUCache(maxsize, getsizeof), typed, lock) |
| 97 |
| 98 |
| 99 def lru_cache(maxsize=128, typed=False, getsizeof=None, lock=_marker): |
| 100 """Decorator to wrap a function with a memoizing callable that saves |
| 101 up to `maxsize` results based on a Least Recently Used (LRU) |
| 102 algorithm. |
| 103 |
| 104 """ |
| 105 from .lru import LRUCache |
| 106 if lock is not _marker: |
| 107 _deprecated("Passing 'lock' to lru_cache()", 3) |
| 108 return _cache(LRUCache(maxsize, getsizeof), typed, lock) |
| 109 |
| 110 |
| 111 def rr_cache(maxsize=128, choice=random.choice, typed=False, getsizeof=None, |
| 112 lock=_marker): |
| 113 """Decorator to wrap a function with a memoizing callable that saves |
| 114 up to `maxsize` results based on a Random Replacement (RR) |
| 115 algorithm. |
| 116 |
| 117 """ |
| 118 from .rr import RRCache |
| 119 if lock is not _marker: |
| 120 _deprecated("Passing 'lock' to rr_cache()", 3) |
| 121 return _cache(RRCache(maxsize, choice, getsizeof), typed, lock) |
| 122 |
| 123 |
| 124 def ttl_cache(maxsize=128, ttl=600, timer=time.time, typed=False, |
| 125 getsizeof=None, lock=_marker): |
| 126 """Decorator to wrap a function with a memoizing callable that saves |
| 127 up to `maxsize` results based on a Least Recently Used (LRU) |
| 128 algorithm with a per-item time-to-live (TTL) value. |
| 129 """ |
| 130 from .ttl import TTLCache |
| 131 if lock is not _marker: |
| 132 _deprecated("Passing 'lock' to ttl_cache()", 3) |
| 133 return _cache(TTLCache(maxsize, ttl, timer, getsizeof), typed, lock) |
OLD | NEW |