Python - cache修饰器:将已经计算过的结果保留下来,可用于记忆化搜索

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python - cache修饰器:将已经计算过的结果保留下来,可用于记忆化搜索相关的知识,希望对你有一定的参考价值。

Python - cache修饰器:将已经计算过的结果保留下来,可用于记忆化搜索

今日在看力扣题解时发现了大佬的“@cache”,发现很方便,就小研究了一番。

实验和结论

先说下结论

cache是functools中的一个用于缓存计算结果的修饰器

from functools import cache

可用于修饰函数

@cache
def myAdd(a, b):
    return a + b

这样做的好处是,对于被修饰的函数,相同的参数只会被真正计算一次。后续再使用相同的参数调用这个函数的话,会直接返回先前已经计算过的结果。

若在程序中第一次调用myAdd(1, 2),则真的会在myAdd函数中计算1 + 2 = 3

但是在程序中再次调用myAdd(1, 2)时,由于之前已经计算过参数为(1, 2)时结果为3,所以这次实际上不会再次计算1 + 2 = ?,而是直接返回3

实验

下面进行验证:

编写两个简单的“加法运算”函数

from functools import cache


def withoutCache(a, b):
    print(a, b)
    c = a + b
    return c


@cache
def withCache(a, b):
    print(a, b)
    c = a + b
    return c

在计算a + b之前,会先进行打印操作,意思是“我要开始计算a+b了”

接着调用这两个函数:

print(withoutCache(1, 2))
print('-' * 10)
print(withoutCache(1, 2))
print('-' * 10)
print(withCache(2, 3))
print('-' * 10)
print(withCache(2, 3))

相当于是用相同的参数对每个函数各调用两次。

我们得到运行结果:

1 2
3
----------
1 2
3
----------
2 3
5
----------
5

可以看到,在第二次调用withCache(2, 3)时,实际上没有真正地计算2 + 3 = ?,而是直接返回了先前已经计算过的5

实现

那么这个修饰器是怎么实现的呢?接下来我们实现一个低配版的cache修饰器

可以参考文章Python - 函数参数中的*和**获取函数中的参数

dic = 

def myCache(func):
    def main(*a):
        if a in dic:
            return dic[a]
        dic[a] = func(*a)
        return dic[a]
    return main


@myCache
def myAdd(a, b):
    print(a, b)
    c = a + b
    return c

print(myAdd(1, 2))
print('-' * 10)
print(myAdd(1, 2))

运行结果:

1 2
3
----------
3

上述只是一个简单的延时,未经优化,且未记录调用函数,多个函数调用时可能会产生冲突。

lru_cache

阅读源码可发现,其实cache修饰器是调用了lru_cache修饰器。

lru(Least Recently Used),即最近最少使用。下面简单介绍一下lru_cache

@lru_cache(maxsize=2, typed=False)
def f(a, b):
    pass

其中maxsize代表最大缓存数量,typed代表是否区分数据类型(typed为True的话将会分别缓存不同类型的数据,例如3和3.0)

同步发文于CSDN,原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/129164772

以上是关于Python - cache修饰器:将已经计算过的结果保留下来,可用于记忆化搜索的主要内容,如果未能解决你的问题,请参考以下文章

Python的修饰器@

python3修饰器简单理解

如何在 python 中使用带有修饰函数的 doctest?

python闭包装饰器

Python 从零学起(纯基础) 笔记 之 迭代器生成器和修饰器

Sphinx 文档没有列出修饰函数的参数