我有一个函数需要很长时间,需要能够缓存自己的结果,以便在使用相同参数再次调用时使用。下面的例子似乎解决了这个问题。我使用的是python3.6
我的问题围绕这一行:
param_sig = repr(locals())
1)有没有一种更具python风格的方法来获得传递给函数的参数的唯一签名?你知道吗
2)我可以依赖Python将函数参数插入locals()映射的顺序吗?同样,这似乎是可行的,但如果需要,我可以在一个不那么优雅的签名创建者中显式地重新列出每个参数,如:
param_sig = "{},{},{}".format(a,b,c)
示例代码:
import random
cached_answers = {}
def f(a=1, b=2, c=3):
param_sig = repr(locals())
if param_sig in cached_answers:
ans = cached_answers[param_sig]
print("Call: {} = CACHED {}".format(param_sig,ans))
return ans
else:
# do heavy lifting then cache the result
ans = random.random()
print("Call: {} = {}".format(param_sig,ans))
cached_answers[param_sig] = ans
return ans
# various calls... some of which are repeated and should be cached
f()
f(b=9)
f(c=9, a=9)
f() # should be cached
parms={'a':9}
f(**parms)
f(b=9) # should be cached
f(a=9) # should be cached
通过使用*args(提供位置参数列表)或**kwargs(一个“关键字”参数的dict)语法提供参数,您可以按确定的顺序访问参数。考虑:
或者
要在缓存中使用这些参数,需要将参数转换为dict键。 我建议使用元组作为缓存键,而不是将其格式化为字符串。元组是不可变的,因此可以对它们进行散列(dict的一个要求)。示例:
repr(locals())
非常糟糕,因为它不适用于此函数。它会起作用,或者可以让它起作用,我可以深入研究一些问题,而不是这样做的语义。你知道吗我会回到问题上来-首先,你的解决方案:
Python有一个缓存函数,就像您在stdlib上的
functools
模块中需要的一样-只需导入它并将其用作装饰器:现在我们来了解为什么decorators有一个更好的解决方案:缓存结果的逻辑根本不与函数的逻辑混合,而且,无论使用什么缓存方法,都可以用于缓存程序中的任何函数—无需在每个函数体中复制缓存代码。你知道吗
您将了解到,虽然Python自己的
lru_cache
与您的情况相匹配,但它并不是最佳匹配,也不是所有情况下都完美的—无论如何,您最好安装第三方软件包进行缓存,或者滚动自己的缓存,但保持逻辑独立。你知道吗可以应用于系统中各种类似函数或方法的特定编程逻辑的思想被称为"aspect oriented programing",Python decorator语法是一种廉价使用它的好方法。你知道吗
除了将逻辑与函数分离,并使用
repr(locals())
来序列化参数之外,您的方法是正确的:保留一个(模块)全局字典,其中包含每组参数的结果是缓存函数的常用方法。lru_cache
只是以一种透明的方式发生的。你知道吗相关问题 更多 >
编程相关推荐