【问题标题】:Caching Decorator Python缓存装饰器 Python
【发布时间】:2015-07-29 09:12:51
【问题描述】:

我正在观看 Raymond Hettinger 的精彩视频之一,我对装饰器示例感到有些困惑:

def cache(func):
    saved={}
    @wraps(func)
    def newfunc(*args):
        if args in saved:
            return newfunc(*args) # should be return saved[args]?
        result = func(*args)
        saved[args]=result
        return result
    return newfunc

我不是装饰器方面的专家,但是在发现项目被缓存时返回对 newfunc(*args) 的调用不会导致递归循环永远不会结束吗?我认为它应该返回 saved[args] (该函数最终返回的结果,这是同一件事,但我认为如果在缓存中找到一个项目,它永远不会到达那里。)

【问题讨论】:

  • 你能说明wraps是如何定义的吗?
  • @Asad:几乎可以肯定是from functools import wraps
  • 您能否链接到视频(最好带有时间戳)——或者,如果他有附加的幻灯片演示文稿,可以链接到幻灯片吗?这看起来肯定是错误的,甚至 Raymond Hettinger 也不会犯愚蠢的错别字。
  • @Solaxun 可能是一个错字。现在定义的方式肯定不使用缓存。

标签: python caching decorator


【解决方案1】:

您也可以使用@functools.lru_cache(maxsize=128, typed=False)¶ 这看起来像:

from functools import lru_cache

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

【讨论】:

  • 如果我们使用“maxsize=2”会更好,因为之前的 2 个缓存值足以计算斐波那契数列。
【解决方案2】:

是的,这是一个错误。

如果你不确定,让我们测试一下:

def fib(n):
    if n < 2:
        return 1
    return fib(n-2) + fib(n-1)

print(fib(10))

@cache
def cfib(n):
    if n < 2:
        return 1
    return cfib(n-2) + cfib(n-1)

print(cfib(10))

第一个打印出89,第二个中止:

  File "rhcache.py", line 8, in newfunc
    return newfunc(*args) # should be return saved[args]?
  File "rhcache.py", line 8, in newfunc
    return newfunc(*args) # should be return saved[args]?
  # ... 997 more copies
RuntimeError: maximum recursion depth exceeded

但如果我们按照您的建议更改它,它会再次打印89。 (而且,如果你计时,它会比非缓存版本运行得更快;如果你分析它,它只会调用 10 次真正的函数;等等)

一切如你所愿。

那么,我们学到了什么?即使是 Raymond Hettinger 也不会在未经测试的代码中偶尔出现拼写错误,但他的代码足够干净,即使不运行也很容易找到并解决问题。 :)

您可以向他发送电子邮件,在 YouTube 页面上添加评论,或在 PyVideo 页面上报告问题。

【讨论】:

  • 不,我不想成为那个在事实发生 2 年后指出一个小错误的烦人……只是想确保我没有遗漏任何东西!感谢您抽出宝贵时间进行验证。
猜你喜欢
  • 1970-01-01
  • 2022-09-29
  • 2013-02-03
  • 1970-01-01
  • 2019-02-19
  • 1970-01-01
  • 1970-01-01
  • 2015-03-24
  • 1970-01-01
相关资源
最近更新 更多