Python: functools
- lru_cache
import functools, time @functools.lru_cache(maxsize=128, typed=False) def b(x, y, z=3): time.sleep(2) return x + y print(b(5, 6)) print('~' * 60) print(b(5, 6)) # immediate print(b(5.0, 6)) # immediate 11
import functools, time @functools.lru_cache(maxsize=128, typed=True) def b(x, y, z=3): time.sleep(2) return x + y print(b(5, 6)) print('~' * 60) print(b(5, 6)) # immediate print(b(5.0, 6)) # not immediate 11.0
import functools, time @functools.lru_cache(maxsize=128, typed=True) def b(x, y=6, z=3): time.sleep(2) return x + y print(b(5, 6)) print('~' * 60) print(b(5)) # not immediate print('~' * 60) print(b(5, y=6)) # not immedate







import functools, time @functools.lru_cache(maxsize=None, typed=False) def b(x, y=6, z=3): time.sleep(2) return x + y print(b(x=5, y=6)) print('~' * 60) print(b(x=5, y=6)) # immediate print('~' * 60) print(b(y=6, x=5)) # not immediate 没有对kwargs进行sorted @functools.lru_cache(maxsize=None, typed=True) def b(x): return x print(b([1, 2])) # TypeError: unhashable type: 'list'

import functools @functools.lru_cache(maxsize=None, typed=False) # 无上限缓存 def fibonacci(n): if n < 0: return None elif n < 2: return n else: return fibonacci(n - 1) + fibonacci(n - 2) print([fibonacci(v) for v in range(40)]) print(fibonacci.cache_info()) print(fibonacci.__wrapped__) print(fibonacci) fibonacci.cache_clear() print(fibonacci.cache_info())







-
lru_cache实现

from functools import wraps import time, inspect def cache(f): local_cache = dict() @wraps(f) def wrapper(*args, **kwargs): print(f'args: {args}, kwargs: {kwargs}') valor = dict() parameters = inspect.signature(f).parameters # OrderedDict keys = list(parameters.keys()) # positional arguments # 遇到VAR_POSITIONAL, 不能依次赋值了 for i, arg in enumerate(args): print(parameters[keys[i]].kind) valor[keys[i]] = arg # keyword arguments # for k, v in kwargs.items(): # valor.setdefault(k, v) valor.update(kwargs) key = tuple(sorted(valor.items())) print(f'key: {key}') if key in local_cache.keys(): return local_cache[key] else: ret = f(*args, **kwargs) local_cache[key] = ret return ret return wrapper @cache def b(x, y=55): time.sleep(2) return x + y # print(b(5, 55)) # print(b(5, 55)) # print(b(y=55, x=5)) # print(b(5)) @cache def p(a, b: int = 5, *args, c=55, d, **kwags): return a + b p(1, 2, 3, 4, 5, d='dd')


from functools import wraps import time, inspect, datetime def duration(f): @wraps(f) def wrapper(*args, **kwargs): commence = datetime.datetime.now() ret = f(*args, **kwargs) delta = (datetime.datetime.now() - commence).total_seconds() print(f'\nfunction {f.__qualname__} elapsed {delta} seconds\n') return ret return wrapper def cache(duration = 3): local_cache = dict() def outer(f): @wraps(f) def wrapper(*args, **kwargs): print(f'args: {args}, kwargs: {kwargs}') def clear_expire_keys(cache: dict): # perish expire keys expire_keys = [] for k, (_, timestamp) in cache.items(): if datetime.datetime.now().timestamp() - timestamp > duration: expire_keys.append(k) for k in expire_keys: cache.pop(k) clear_expire_keys(local_cache) def make_key(f, *args, **kwargs): valor = dict() parameters = inspect.signature(f).parameters # OrderedDict keys = list(parameters.keys()) print(f'keys: {keys}') # positional arguments # 遇到VAR_POSITIONAL, 不能依次赋值了 for i, v in enumerate(args): # print(parameters[keys[i]].kind, type(str(parameters[keys[i]].kind))) if parameters[keys[i]].kind.name == 'VAR_POSITIONAL': # 判断是否为VAR_POSITIONAL valor.setdefault(keys[i], tuple()) valor[keys[i]] += args[i:] break valor[keys[i]] = v keys.remove(keys[i]) # 移除已经加入valor的参数 # keyword arguments # valor.update(kwargs) # 会产生参数覆盖问题 for k, v in kwargs.items(): if k in valor: raise TypeError(f'{f.__qualname__}() got multiple values for argument {repr(k)}') valor.update({k: v}) keys.remove(k) # 移除已经加入valor的参数 # 在计算key前, 把未传递的默认值参数加入到valor, args, kwargs一定没有默认值 print(f'keys: {keys}') for item in keys: if parameters[item].default != parameters[item].empty: valor.update({item: parameters[item].default}) return tuple(sorted(valor.items())) key = make_key(f, *args, **kwargs) # 计算local_cache的 key print(f'key: {key}') if key not in local_cache.keys(): local_cache[key] = f(*args, **kwargs), datetime.datetime.now().timestamp() return local_cache[key] # if key in local_cache.keys(): # return local_cache[key] # else: # ret = f(*args, **kwargs) # local_cache[key] = ret # # return ret return wrapper return outer @duration @cache() def b(x, y = 55): time.sleep(2) return x + y # print(b(5, 55)) # print(b(5, 55, x=5, y=55)) # valor.update(kwargs), b(5, 55) 调用后, local_cache缓存 key: (('x', 5), ('y', 55)), 直接返回, 不会传参给原函数, 在对kwargs合并时, 做检查 # print(b(5, 55, x=55, y=55)) # local_cache 找不到 key: (('x', 55), ('y', 55)) 时, 会传参给原函数, 异常 # print(b(5, y=55)) # print(b(5)) # print(b(5, 55)) # print(b(y=55, x=5)) # print(b(5)) @duration @cache(duration = 4) def p(a, b: int = 5, *args, c = 55, d, **kwargs): time.sleep(2) return a + b print(p(1, d = 'dd')) time.sleep(3.5) print(p(1, b = 5, d = 'dd')) print(p(1, b = 5, c = 55, d = 'dd')) # print(p(1, 2, 3, 4, 5, d='dd'))

浙公网安备 33010602011771号