自定义缓存装饰器(TTL过期/LRU/文件持久化)
请展示如何实现一个支持TTL过期时间的自定义缓存装饰器、一个基于磁盘的文件缓存装饰器,以及一个带最大大小限制的LRU缓存装饰器。对比functools内置缓存和自定义缓存的优缺点。
回答
我还是少年
1. TTL过期缓存
import time
from functools import wraps
def ttl_cache(seconds=60):
def decorator(func):
cache = {}
@wraps(func)
def wrapper(*args, **kwargs):
key = args + tuple(sorted(kwargs.items()))
now = time.time()
if key in cache and now - cache[key][1] < seconds:
return cache[key][0]
result = func(*args, **kwargs)
cache[key] = (result, now)
return result
wrapper.cache = cache
return wrapper
return decorator
@ttl_cache(seconds=30)
def get_user(user_id):
return db.query(f'SELECT * FROM users WHERE id={user_id}')
2. 文件缓存装饰器
import json
import os
from functools import wraps
def file_cache(cache_dir='/tmp/cache'):
os.makedirs(cache_dir, exist_ok=True)
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
key = f'{func.__name__}_{hash(args)}_{hash(tuple(kwargs.items()))}'
cache_path = os.path.join(cache_dir, f'{key}.json')
if os.path.exists(cache_path):
with open(cache_path) as f:
return json.load(f)
result = func(*args, **kwargs)
with open(cache_path, 'w') as f:
json.dump(result, f)
return result
return wrapper
return decorator
3. 大小受限LRU缓存
from collections import OrderedDict
def lru_cache_custom(maxsize=128):
def decorator(func):
cache = OrderedDict()
@wraps(func)
def wrapper(*args, **kwargs):
key = args + tuple(sorted(kwargs.items()))
if key in cache:
cache.move_to_end(key)
return cache[key]
result = func(*args, **kwargs)
cache[key] = result
if len(cache) > maxsize:
cache.popitem(last=False)
return result
return wrapper
return decorator
对比
| 特性 | functools内置 | 自定义 |
|---|---|---|
| TTL过期 | 不支持 | 支持 |
| 文件持久化 | 不支持 | 支持 |
| 分布式缓存 | 不支持 | 支持 |
| 线程安全 | 不支持 | 可选 |
| 开发维护 | 零成本 | 需自测 |
**建议:**多数场景用内置lru_cache/cache;需要TTL/持久化时用cachetools库或自定义。