缓存函数结果的函数装饰器 [英] Function decorator that caches function results

查看:101
本文介绍了缓存函数结果的函数装饰器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


www.mathschallenge.net ,我注意到一些长时间运行的函数可以通过缓存它们的函数结果并从

缓存中检索而不是再次计算来帮助* b $ b。这意味着我经常可以使用

自然递归实现,而不是解除递归的

调用,以避免大的指数运行时间。


好​​的,所以我想,如果可能的话,创建一个缓存

函数结果并从缓存中检索它们的装饰器怎么样,否则它会调用函数和存储下一次调用的缓存中的值。


这是我到目前为止所提出的:


def cache_function(fn):

cache = {}

def cached_result(* args,** kwargs):

如果缓存中的args:

返回缓存[args]

result = fn(* args,** kwargs)

cache [args] =结果

返回结果

返回cached_result


使用示例:


@cache_function

def fibonacci (idx):

如果idx在(1,2):

返回1

否则:

返回fibonacci(idx-1)+ fibonacci(idx-2)

指数范围内(1,101):

打印指数,斐波那契(指数)


这个例子从指数时间跑到接近

瞬间。


但是,这个:


索引在范围(1,101):

打印索引,斐波那契(idx =索引)


这个使用kwargs参数列表,而我''我不知道如何改变我的功能以便将其考虑在内。


有没有人知道如何做到这一点?


解决方案必须将斐波那契(50)和斐波那契(idx =

50)视为同一个调用,从而从缓存中检索第二个。


-

Lasse V?gs?ther Karlsen
http://usinglvkblog.blogspot.com/

mailto:la *** @ vkarlsen.no

PGP KeyID: 0x2A42A1C2

解决方案

Lasse V?gs?ther Karlsen写道:

但是,这个:

索引范围(1,101):
打印索引,斐波那契( idx = index)

这个使用kwargs参数列表,我不知道如何改变我的功能以考虑到这一点。
有没有人知道如何做到这一点?

解决方案必须将斐波那契(50)和斐波纳契(idx =
50)视为同一个呼叫,从而检索缓存中的第二个。




你的大部分收益来自缓存递归调用,而不是来自缓存

原始调用。 />

如果解决方案不认为关键字参数等同于位置

参数,它将* * *调用真实函数,然后

递归调用仍然会从缓存中出来,所以最终结果将是b / b
仍然可以提供你想要的几乎所有加速。


除非存储在缓存中的结果是非常大的数据结构,否则我建议您只需将(args,kwargs)存储为缓存键并且

接受有时你会多次缓存同一个电话的命中。


2005年10月8日星期六下午01:53:28 + 0000,Duncan Booth写道:

除非存储在缓存中的结果是非常大的数据结构,否则我建议您只存储(args,kwargs)作为缓存键和




...除了dicts不能是dict键


另一个''memoize''装饰器使用它来获取密钥:

kw = kwargs.items()

kw.sort()

key =(args,tuple(kw))
http://aspn.activestate.com /ASPN/Coo.../Recipe/325905


杰夫


-----开始PGP签名 - ---

版本:GnuPG v1.4.1(GNU / Linux)

iD8DBQFDR9vXJd01MZaTXX0RAq5 + AJ4yVo8MbputurPvObHBdt urrhZ70gCfUpN2

HxoUEMfpxhkFW3FUDVR + Qkg =

= 4UHm

-----结束PGP签名-----


怎么不存储args呢?这样的事情:


def cache_function(func,args_list):

cache = {}

def cached_result(* args, ** kwargs):

kwargs.update(dict(zip(args_list,args)))

如果缓存中的kwargs:

返回缓存[kwargs]

result = func(** kwargs)

cache [kwargs] =结果

返回结果

return cached_result


args_list是所有参数名称的列表,因此可以将它们转换为关键字参数。

After working through a fair number of the challenges at
www.mathschallenge.net, I noticed that some long-running functions can
be helped *a lot* by caching their function results and retrieving from
cache instead of calculating again. This means that often I can use a
natural recursive implementation instead of unwinding the recursive
calls to avoid big exponential running-times.

Ok, so I thought, how about creating a decorator that caches the
function results and retrieves them from cache if possible, otherwise it
calls the function and store the value in the cache for the next invokation.

This is what I came up with so far:

def cache_function(fn):
cache = {}
def cached_result(*args, **kwargs):
if args in cache:
return cache[args]
result = fn(*args, **kwargs)
cache[args] = result
return result
return cached_result

Example of usage:

@cache_function
def fibonacci(idx):
if idx in (1, 2):
return 1
else:
return fibonacci(idx-1) + fibonacci(idx-2)

for index in range(1, 101):
print index, fibonacci(index)

this example goes from taking exponential time to run to being near
instantaneous.

However, this:

for index in range(1, 101):
print index, fibonacci(idx = index)

this one uses the kwargs list of arguments, and I''m not sure how to
change my function to take that into account.

Does anyone have any clues as to how to do that?

The solution would have to consider fibonacci(50) and fibonacci(idx =
50) as the same call and thus retrieve the second one from the cache.

--
Lasse V?gs?ther Karlsen
http://usinglvkblog.blogspot.com/
mailto:la***@vkarlsen.no
PGP KeyID: 0x2A42A1C2

解决方案

Lasse V?gs?ther Karlsen wrote:

However, this:

for index in range(1, 101):
print index, fibonacci(idx = index)

this one uses the kwargs list of arguments, and I''m not sure how to
change my function to take that into account.

Does anyone have any clues as to how to do that?

The solution would have to consider fibonacci(50) and fibonacci(idx =
50) as the same call and thus retrieve the second one from the cache.



Most of your gain comes from caching the recursive calls, not from caching
the original call.

If the solution doesn''t consider keyword arguments equivalent to positional
arguments, it will make *one* call to the real function, and then the
recursive call will still come out of the cache, so the net result will
still be to give you almost all the speedup you wanted.

Unless the results stored in the cache are very large data structures, I
would suggest that you simply store (args,kwargs) as the cache key and
accept the hit that sometime you''ll cache the same call multiple times.


On Sat, Oct 08, 2005 at 01:53:28PM +0000, Duncan Booth wrote:

Unless the results stored in the cache are very large data structures, I
would suggest that you simply store (args,kwargs) as the cache key and
accept the hit that sometime you''ll cache the same call multiple times.



... except that dicts cannot be dict keys

Another ''memoize'' decorator uses this to get the key:
kw = kwargs.items()
kw.sort()
key = (args, tuple(kw))
http://aspn.activestate.com/ASPN/Coo.../Recipe/325905

Jeff

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFDR9vXJd01MZaTXX0RAq5+AJ4yVo8MbputurPvObHBdt urrhZ70gCfUpN2
HxoUEMfpxhkFW3FUDVR+Qkg=
=4UHm
-----END PGP SIGNATURE-----


What about not storing args at all? Something like this:

def cache_function(func, args_list):
cache = {}
def cached_result(*args, **kwargs):
kwargs.update(dict(zip(args_list, args)))
if kwargs in cache:
return cache[kwargs]
result = func(**kwargs)
cache[kwargs] = result
return result
return cached_result

args_list is a list of all the argument names, so that they can be
converted into keyword arguments.


这篇关于缓存函数结果的函数装饰器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆