我正在使用 Python 装饰器来实现函数的缓存。我了解缓存结果以提高性能的基本概念,但我正在努力解决如何处理不同的函数参数并确保底层数据更改时缓存更新。
我已经实现了一个基本装饰器,它将函数结果存储在基于参数的字典。但是,此方法无法处理函数参数可能具有复杂结构(如嵌套列表)或函数依赖的基础数据可能被修改的情况。
`def simple_cache(func): 缓存={} def 包装器(*args,**kwargs): key = (args, kwargs) # 基于参数的基本键 如果密钥不在缓存中: 缓存[键] = func(*args, **kwargs) 返回缓存[key] 返回包装
@simple_cache defcalculate_something(data):
模拟复杂计算
...
返回结果 `
对 Python 装饰器缓存的理解非常好,并且已经确定了使用简单字典作为缓存机制的局限性。让我们来解决这些局限性,并探索一些更强大的缓存技术:
1. 处理复杂参数
-
哈希:
不是直接使用可变结构(如列表或字典)作为键,而是使用哈希函数。 Python 的内置
hash()
函数可以处理不可变类型,但对于可变结构,需要一个强大的哈希函数,比如来自hashlib
的函数。但是,确保的哈希函数适合的数据类型,并且可以很好地防止冲突。
```python import hashlib
def simple_cache(func): cache = {} def wrapper( args, kwargs): key = hashlib.md5(str((args, kwargs)).encode()).hexdigest() # 创建更稳定的哈希 if key not in cache: cache[key] = func( args, **kwargs) return cache[key] return wrapper ```
-
参数序列化:
另一个选择是使用
pickle
或json
等模块将参数序列化为不可变字符串。这在处理复杂结构时效果很好,但会带来额外的开销。
```python import json
def simple_cache(func): cache = {} def wrapper( args, kwargs): key = json.dumps((args, kwargs)) if key not in cache: cache[key] = func( args, **kwargs) return cache[key] return wrapper ```
2. 处理数据更改
-
基于时间的失效:
为缓存条目设置过期时间,以便在设定的时间间隔后刷新它们。这可以通过使用
time
模块或为每个缓存条目存储时间戳来实现。
```python import time
def timed_cache(seconds=300): # 默认缓存时间为 5 分钟 def decorator(func): cache = {} def wrapper( args, kwargs): key = (args, kwargs) now = time.time() if key not in cache or now - cache[key][1] > seconds: cache[key] = (func( args, **kwargs), now) return cache[key][0] return wrapper return decorator ```
- 基于事件的失效: 当知道依赖的数据已更改时,手动使缓存失效。这需要更复杂的设置,但可以实现更精细的控制。可以引入一个机制,在基础数据更新时清除缓存或使特定条目无效。
```python def event_based_cache(cache): # 使用共享缓存 def decorator(func): def wrapper( args, kwargs): key = (args, kwargs) if key not in cache: cache[key] = func( args, **kwargs) return cache[key] return wrapper
# 在其他地方,当数据更改时: cache.clear() # 或使特定键无效 ```
3. 使用
functools.lru_cache
Python 的标准库提供了
functools.lru_cache
装饰器,它可以处理缓存,包括基于最近最少使用 (LRU) 算法的自动失效。这是一个高效且易于使用的选择,尤其是对于一般的缓存目的。
from functools import lru_cache
@lru_cache(maxsize=128) # 缓存最多 128 个结果
def calculate_something(data):
# ...
return result
请记住,最佳缓存策略取决于的具体需求和应用程序的行为。仔细考虑参数的性质、数据更改的频率以及所需的缓存失效级别。
标签:python,function,caching,arguments,decorator From: 78791684