python 来自http://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators/
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 来自http://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators/相关的知识,希望对你有一定的参考价值。
def lfu_cache(maxsize=100):
'''Least-frequenty-used cache decorator.
Arguments to the cached function must be hashable.
Cache performance statistics stored in f.hits and f.misses.
Clear the cache with f.clear().
http://en.wikipedia.org/wiki/Least_Frequently_Used
@Bradley-Ayers : I slightly modified lfu_cache to avoid a problem when
everything in the cache has been called at least twice.
In this scenario, the new function call will be added to the cache,
but will be immediately removed (as it has less hits than everything else).
'''
def decorating_function(user_function):
cache = {} # mapping of args to results
use_count = Counter() # times each key has been accessed
kwarg_mark = object() # separate positional and keyword args
@functools.wraps(user_function)
def wrapper(*args, **kwargs):
key = args
if kwargs:
key += (kwarg_mark,) + tuple(sorted(kwargs.items()))
# get cache entry or compute if not found
try:
result = cache[key]
use_count[key] += 1
wrapper.hits += 1
except KeyError:
# need to add something to the cache, make room if necessary
if len(cache) == maxsize:
for k, _ in nsmallest(maxsize // 10 or 1,
use_count.iteritems(),
key=itemgetter(1)):
del cache[k], use_count[k]
cache[key] = user_function(*args, **kwargs)
result = cache[key]
use_count[key] += 1
wrapper.misses += 1
return result
def clear():
cache.clear()
use_count.clear()
wrapper.hits = wrapper.misses = 0
wrapper.hits = wrapper.misses = 0
wrapper.clear = clear
wrapper.cache = cache
return wrapper
return decorating_function
import collections
import functools
def lru_cache(maxsize=100):
'''Least-recently-used cache decorator.
Arguments to the cached function must be hashable.
Cache performance statistics stored in f.hits and f.misses.
http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
'''
def decorating_function(user_function):
cache = collections.OrderedDict() # order: least recent to most recent
@functools.wraps(user_function)
def wrapper(*args, **kwds):
key = args
if kwds:
key += tuple(sorted(kwds.items()))
try:
result = cache.pop(key)
wrapper.hits += 1
except KeyError:
result = user_function(*args, **kwds)
wrapper.misses += 1
if len(cache) >= maxsize:
cache.popitem(0) # purge least recently used cache entry
cache[key] = result # record recent use of this key
return result
wrapper.hits = wrapper.misses = 0
return wrapper
return decorating_function
# this implementation appears to be about 50% faster (using -m profile and
# your __main__ method as the performance test):
import time
import heapq
def memoize(maxsize):
"""decorator to 'memoize' a function - caching its results
@sasa sasa
"""
def decorating_function(f):
cache = {} # map from key to value
heap = [] # list of keys, in LRU heap
cursize = 0 # because len() is slow
def wrapper(*args):
key = repr(args)
# performance crap
_cache=cache
_heap=heap
_heappop = heapq.heappop
_heappush = heapq.heappush
_time = time.time
_cursize = cursize
_maxsize = maxsize
if not _cache.has_key(key):
if _cursize == _maxsize:
# pop oldest element
(_,oldkey) = _heappop(_heap)
_cache.pop(oldkey)
else:
_cursize += 1
# insert this element
_cache[key] = f(*args)
_heappush(_heap,(_time(),key))
wrapper.misses += 1
else:
wrapper.hits += 1
return cache[key]
wrapper.__doc__ = f.__doc__
wrapper.__name__ = f.__name__
wrapper.hits = wrapper.misses = 0
return wrapper
return decorating_function
import collections
import functools
from itertools import ifilterfalse
from heapq import nsmallest
from operator import itemgetter
class Counter(dict):
'Mapping where default values are zero'
def __missing__(self, key):
return 0
def lru_cache(maxsize=100):
'''Least-recently-used cache decorator.
Arguments to the cached function must be hashable.
Cache performance statistics stored in f.hits and f.misses.
Clear the cache with f.clear().
http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
'''
maxqueue = maxsize * 10
def decorating_function(user_function,
len=len, iter=iter, tuple=tuple, sorted=sorted, KeyError=KeyError):
cache = {} # mapping of args to results
queue = collections.deque() # order that keys have been used
refcount = Counter() # times each key is in the queue
sentinel = object() # marker for looping around the queue
kwd_mark = object() # separate positional and keyword args
# lookup optimizations (ugly but fast)
queue_append, queue_popleft = queue.append, queue.popleft
queue_appendleft, queue_pop = queue.appendleft, queue.pop
@functools.wraps(user_function)
def wrapper(*args, **kwds):
# cache key records both positional and keyword args
key = args
if kwds:
key += (kwd_mark,) + tuple(sorted(kwds.items()))
# record recent use of this key
queue_append(key)
refcount[key] += 1
# get cache entry or compute if not found
try:
result = cache[key]
wrapper.hits += 1
except KeyError:
result = user_function(*args, **kwds)
cache[key] = result
wrapper.misses += 1
# purge least recently used cache entry
if len(cache) > maxsize:
key = queue_popleft()
refcount[key] -= 1
while refcount[key]:
key = queue_popleft()
refcount[key] -= 1
del cache[key], refcount[key]
# periodically compact the queue by eliminating duplicate keys
# while preserving order of most recent access
if len(queue) > maxqueue:
refcount.clear()
queue_appendleft(sentinel)
for key in ifilterfalse(refcount.__contains__,
iter(queue_pop, sentinel)):
queue_appendleft(key)
refcount[key] = 1
return result
def clear():
cache.clear()
queue.clear()
refcount.clear()
wrapper.hits = wrapper.misses = 0
wrapper.hits = wrapper.misses = 0
wrapper.clear = clear
return wrapper
return decorating_function
def lfu_cache(maxsize=100):
'''Least-frequenty-used cache decorator.
Arguments to the cached function must be hashable.
Cache performance statistics stored in f.hits and f.misses.
Clear the cache with f.clear().
http://en.wikipedia.org/wiki/Least_Frequently_Used
'''
def decorating_function(user_function):
cache = {} # mapping of args to results
use_count = Counter() # times each key has been accessed
kwd_mark = object() # separate positional and keyword args
@functools.wraps(user_function)
def wrapper(*args, **kwds):
key = args
if kwds:
key += (kwd_mark,) + tuple(sorted(kwds.items()))
use_count[key] += 1
# get cache entry or compute if not found
try:
result = cache[key]
wrapper.hits += 1
except KeyError:
result = user_function(*args, **kwds)
cache[key] = result
wrapper.misses += 1
# purge least frequently used cache entry
if len(cache) > maxsize:
for key, _ in nsmallest(maxsize // 10,
use_count.iteritems(),
key=itemgetter(1)):
del cache[key], use_count[key]
return result
def clear():
cache.clear()
use_count.clear()
wrapper.hits = wrapper.misses = 0
wrapper.hits = wrapper.misses = 0
wrapper.clear = clear
return wrapper
return decorating_function
if __name__ == '__main__':
@lru_cache(maxsize=20)
def f(x, y):
return 3*x+y
domain = range(5)
from random import choice
for i in range(1000):
r = f(choice(domain), choice(domain))
print(f.hits, f.misses)
@lfu_cache(maxsize=20)
def f(x, y):
return 3*x+y
domain = range(5)
from random import choice
for i in range(1000):
r = f(choice(domain), choice(domain))
print(f.hits, f.misses)
以上是关于python 来自http://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators/的主要内容,如果未能解决你的问题,请参考以下文章
来自 Black Hat Python 书的 Python 嗅探
“路径 python3(来自 --python=python3)不存在”错误