Python内置装饰器:@lru_cache
和 @cache
@lru_cache
和 @cache
是Python标准库中提供的两种缓存装饰器,它们可以将函数计算的结果缓存起来,下次调用的时候直接返回结果
@lru_cache
@lru_cache
装饰器位于 functools
模块中,它使用最近最少使用(LRU)算法来缓存函数调用的结果。当你使用这个装饰器时,函数的调用结果将根据参数被缓存起来。如果再次出现相同的参数,函数将直接从缓存中获取结果,而不是重新执行,从而提高效率。
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_function(param):
# 进行一些计算密集型的操作
return result
在上面的例子中,expensive_function
是一个计算密集型的函数,我们使用 @lru_cache
来缓存它的结果。maxsize
参数指定了缓存中可以存储的最大调用次数。如果没有设置 maxsize
或者设置为 None
,则缓存不会自动清除,但可能会消耗大量内存。
@cache
@cache
装饰器是Python 3.10中引入的新特性,它提供了一个简单的缓存机制。与 @lru_cache
不同,@cache
不需要任何外部库,它是内建于Python中的。@cache
装饰器的工作原理类似于 @lru_cache
,但它更简洁,且默认情况下不限制缓存大小。
def expensive_function(param):
# 进行一些计算密集型的操作
return result
expensive_function = cache(expensive_function)
或者使用装饰器的语法:
@cache
def expensive_function(param):
# 进行一些计算密集型的操作
return result
注意
@lru_cache(maxsize=None) 与@cache 看起来是一样的,但是因为@cache内部不涉及缓存容量管理和调度等操作,理论上是要比@lru_cache(maxsize=None)更快的,在不需要管理缓存容量的时候,选择 @cache 可能更优
示例
leetcode808. 分汤
有 A 和 B 两种类型 的汤。一开始每种类型的汤有 n 毫升。有四种分配操作:
- 提供 100ml 的 汤A 和 0ml 的 汤B 。
- 提供 75ml 的 汤A 和 25ml 的 汤B 。
- 提供 50ml 的 汤A 和 50ml 的 汤B 。
- 提供 25ml 的 汤A 和 75ml 的 汤B 。
当我们把汤分配给某人之后,汤就没有了。每个回合,我们将从四种概率同为 0.25 的操作中进行分配选择。如果汤的剩余量不足以完成某次操作,我们将尽可能分配。当两种类型的汤都分配完时,停止操作。
注意
不存在先分配 100 ml 汤B 的操作。
需要返回的值
: 汤A 先分配完的概率 + 汤A和汤B 同时分配完的概率 / 2。返回值在正确答案 10e-5 的范围内将被认为是正确的。
思路
直接模拟整个分汤的过程即可,类似于遍历一棵四叉树。叶子结点的概率根据题面写即可,分支结点的概率就是其子结点概率之和乘以0.25(条件概率的知识)
我们会发现这样做可能会出现可以从多条路径都能到达同一个结点的情况,比如 【操作2,操作4】 【操作3,操作3】和【操作4,操作2】会到达同一个节点。这就会导致不必要的重复计算。
这里我们就需要用到记忆化搜索
。也就是将计算的结果保存下来,下一次直接使用。
手动实现就不说了,这里我们直接使用@cache
即可
代码
class Solution:
def soupServings(self, n: int) -> float:
if n>4476:
return 1
actions=[(100,0),(75,25),(50,50),(25,75)]
@cache
def fun(a,b):
ret=0
for action_a,action_b in actions:
if a<=action_a and b>action_b:
ret+=0.25
elif a<=action_a and b<=action_b:
ret+=0.125
elif a>action_a and b>action_b:
ret += fun(a-action_a,b-action_b)*0.25
return ret
return fun(n,n)
2024/4/2