缓存装饰器通过存储函数的返回值来提高重复调用时的效率,尤其适用于计算密集型或IO操作频繁的场景。本章将深入探讨几种实现缓存逻辑的方式。
4.1 使用functools.lru_cache
Python标准库中的functools.lru_cache是最简便的缓存装饰器实现方式 ,它实现了最近最少使用(Least Recently Used)缓存策略。
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 首次计算并缓存结果
print(fibonacci(10)) # 直接从缓存中获取结果
这里,maxsize参数指定了缓存的容量,当超过限制时,最近最少使用的项会被移除。
4.2 自定义缓存逻辑
有时,标准库提供的缓存策略可能不满足特定需求 ,这时可以自定义缓存逻辑。
class CustomCache:
def __init__(self):
self.cache = {}
def __call__(self, func):
def wrapper(*args, **kwargs):
key = (args, frozenset(kwargs.items()))
if key not in self.cache:
self.cache[key] = func(*args, **kwargs)
return self.cache[key]
return wrapper
@CustomCache()
def expensive_function(x):
print("Calculating...")
return x ** 2
print(expensive_function(5)) # 计算并缓存
print(expensive_function(5)) # 从缓存中返回结果
自定义缓存类提供了灵活性,可根据具体需求调整缓存策略,例如添加过期时间、容量限制等。
4.3 考虑时效性的缓存策略
对于那些结果随时间变化的函数 ,引入时效性至缓存策略是必要的。
from datetime import datetime, timedelta
from functools import wraps
def cache_with_ttl(ttl=timedelta(seconds=5)):
def decorator(func):
cache = {}
@wraps(func)
def wrapper(*args, **kwargs):
now = datetime.now()
key = (args, frozenset(kwargs.items()))
if key not in cache or now - cache[key][1] > ttl:
cache[key] = (func(*args, **kwargs), now)
return cache[key][0]
return wrapper
return decorator
@cache_with_ttl(timedelta(seconds=2))
def time_sensitive_data():
print("Fetching data...")
return datetime.now()
print(time_sensitive_data()) # 首次获取数据
time.sleep(3)
print(time_sensitive_data()) # 仍在缓存期内,返回旧数据
time.sleep(3)
print(time_sensitive_data()) # 缓存已过期,重新获取数据
通过为缓存结果附加时间戳,我们可以实施一个带有时间限制的缓存策略 ,确保数据的新鲜度。
综上所述 ,无论是使用内置的lru_cache,自定义缓存逻辑,还是引入时效性策略 ,缓存装饰器都是提升程序效率的有效手段,尤其在处理昂贵运算时。正确应用缓存策略,可以让程序在保持响应速度的同时减少不必要的资源消耗。