仅使用参数子集作为标识符来缓存 Python 函数结果
Caching Python function results using only subset of arguments as identifier
有没有一种简单的方法可以根据单个标识符参数在 python 中缓存函数结果?例如,假设我的函数有 3 个参数 arg1
、arg2
和 id
。有没有一种简单的方法可以仅根据 id
的值来缓存函数结果?也就是说,无论何时 id
取相同的值,缓存的函数都会 return 相同的结果,而不管 arg1
和 arg2
.
背景:
我有一个耗时且重复调用的函数,其中 arg1
和 arg2
是由大型numpy数组组成的列表和字典。因此,functools.lru_cache
不能按原样工作。然而,arg1
和 arg2
只有少数特定组合。因此我的想法是手动指定一些 id
,它为 arg1
和 arg2
.
的每个可能组合取一个唯一值
我认为您可以将过多的参数移至单独的函数(调用方),如下所示:
import functools
def get_and_update(a, b, c):
return {'a': a, 'b': b, 'c': c}
# ->
@functools.lru_cache
def get_by_a(a):
return {}
def get_and_update(a, b, c):
res = get_by_a(a)
res.update(a=a, b=b, c=c)
return res
x1 = get_and_update('x', 1, 2)
x2 = get_and_update('x', 2, 3)
assert x1 is x2
print(x1, x2, sep='\n')
{'a': 'x', 'b': 2, 'c': 3}
{'a': 'x', 'b': 2, 'c': 3}
def cache(fun):
cache.cache_ = {}
def inner(arg1, arg2, id):
if id not in cache.cache_:
print(f'Caching {id}') # to check when it is cached
cache.cache_[id] = fun(arg1, arg2, id)
return cache.cache_[id]
return inner
@cache
def function(arg1, arg2, arg3):
print('something')
您可以按照 DarrylG 的建议创建自己的装饰器。您可以在 if id not in cache.cache_:
中执行 print(cache.cache_)
以检查它是否仅缓存 id
.
的较新值
您可以使用 cache.cache_
使 cache_
成为函数属性 PEP 232。然后当你想重置cache_
时你可以使用cache.cache_.clear()
。这将使您可以直接访问缓存结果的字典。
function(1, 2, 'a')
function(11, 22, 'b')
function(11, 22, 'a')
function([111, 11], 222, 'a')
print(f'Cache {cache.cache_}') # view previously cached results
cache.cache_.clear() # clear cache
print(f'Cache {cache.cache_}') # cache is now empty
# call some function again to populate cache
function(1, 2, 'a')
function(11, 22, 'b')
function(11, 22, 'a')
function([111, 11], 222, 'a')
编辑:
解决@Bob (OP) 的新评论,在大多数情况下 return 对同一对象的引用就足够了,但 OP 的用例似乎需要答案的新副本,这可能是由于 function(arg1, arg2, arg3)
根据 arg1
、arg_2
和 arg3
被视为唯一(在“cache
”函数中唯一性仅使用 id
定义)。在这种情况下,return对可变对象的相同引用会导致不良行为。如同一评论中所述,inner
函数中的 return 语句应从 return cache.cache_[id]
更改为 return copy.deepcopy(cache.cache_[id])
。
有没有一种简单的方法可以根据单个标识符参数在 python 中缓存函数结果?例如,假设我的函数有 3 个参数 arg1
、arg2
和 id
。有没有一种简单的方法可以仅根据 id
的值来缓存函数结果?也就是说,无论何时 id
取相同的值,缓存的函数都会 return 相同的结果,而不管 arg1
和 arg2
.
背景:
我有一个耗时且重复调用的函数,其中 arg1
和 arg2
是由大型numpy数组组成的列表和字典。因此,functools.lru_cache
不能按原样工作。然而,arg1
和 arg2
只有少数特定组合。因此我的想法是手动指定一些 id
,它为 arg1
和 arg2
.
我认为您可以将过多的参数移至单独的函数(调用方),如下所示:
import functools
def get_and_update(a, b, c):
return {'a': a, 'b': b, 'c': c}
# ->
@functools.lru_cache
def get_by_a(a):
return {}
def get_and_update(a, b, c):
res = get_by_a(a)
res.update(a=a, b=b, c=c)
return res
x1 = get_and_update('x', 1, 2)
x2 = get_and_update('x', 2, 3)
assert x1 is x2
print(x1, x2, sep='\n')
{'a': 'x', 'b': 2, 'c': 3}
{'a': 'x', 'b': 2, 'c': 3}
def cache(fun):
cache.cache_ = {}
def inner(arg1, arg2, id):
if id not in cache.cache_:
print(f'Caching {id}') # to check when it is cached
cache.cache_[id] = fun(arg1, arg2, id)
return cache.cache_[id]
return inner
@cache
def function(arg1, arg2, arg3):
print('something')
您可以按照 DarrylG 的建议创建自己的装饰器。您可以在 if id not in cache.cache_:
中执行 print(cache.cache_)
以检查它是否仅缓存 id
.
您可以使用 cache.cache_
使 cache_
成为函数属性 PEP 232。然后当你想重置cache_
时你可以使用cache.cache_.clear()
。这将使您可以直接访问缓存结果的字典。
function(1, 2, 'a')
function(11, 22, 'b')
function(11, 22, 'a')
function([111, 11], 222, 'a')
print(f'Cache {cache.cache_}') # view previously cached results
cache.cache_.clear() # clear cache
print(f'Cache {cache.cache_}') # cache is now empty
# call some function again to populate cache
function(1, 2, 'a')
function(11, 22, 'b')
function(11, 22, 'a')
function([111, 11], 222, 'a')
编辑:
解决@Bob (OP) 的新评论,在大多数情况下 return 对同一对象的引用就足够了,但 OP 的用例似乎需要答案的新副本,这可能是由于 function(arg1, arg2, arg3)
根据 arg1
、arg_2
和 arg3
被视为唯一(在“cache
”函数中唯一性仅使用 id
定义)。在这种情况下,return对可变对象的相同引用会导致不良行为。如同一评论中所述,inner
函数中的 return 语句应从 return cache.cache_[id]
更改为 return copy.deepcopy(cache.cache_[id])
。