将`functools.lru_cache`应用于lambda函数

8

我在Python中使用递归lambda函数来计算斐波那契数列。我选择递归是因为它最容易用lambda实现。

fib = lambda n: fib(n - 1) + fib(n - 2) if n > 1 else 1

因为使用递归,同样的斐波那契值被多次计算,我认为使用缓存装饰器会有帮助,而且我知道functools.lru_cache是一个简单的选择。
我知道你不能像普通函数一样对lambda函数使用@functools.lru_cache装饰器,但当我尝试这样做时:
fib = functools.lru_cache((lambda n: fib(n - 1) + fib(n - 2) if n > 1 else 1), maxsize = None)

我收到一个错误提示,说functools.lru_cache不会接受函数对象作为参数。

>>> fib = functools.lru_cache((lambda n: fib(n - 1) + fib(n - 2) if n > 1 else 1), maxsize = None)
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    fib = functools.lru_cache((lambda n: fib(n - 1) + fib(n - 2) if n > 1 else 1), maxsize = None)
TypeError: lru_cache() got multiple values for argument 'maxsize'

我查看了文档,发现functools.lru_cache只接受maxsizetyped两个参数,默认值分别为128False
有没有更巧妙的方法可以将装饰器分配给函数,而不仅仅是定义函数而不使用lambda,然后应用装饰器?
2个回答

12

尝试 fib = functools.lru_cache()(lambda n: fib(n - 1) + fib(n - 2) if n > 1 else 1)

我认为调用lru_cache返回一个函数,该函数接受一个函数并返回一个函数。要提供最大大小,请使用fib = functools.lru_cache(100)(lambda n: fib(n - 1) + fib(n - 2) if n > 1 else 1)


5
这是因为lru_cache()返回的是一个装饰器生成器(decorator factory),而不是装饰器本身。它可以用来生成装饰器。 - Cyphase
谢谢!一开始我不明白为什么它能工作,但在终端和源代码中调试了一番后,我明白了:lru_cache函数返回另一个装饰器函数!真聪明! - user3917838
@Cyphase 他们为什么要做那种设计决定呢? - user3917838
2
因为当作装饰器使用时,这看起来非常自然(这是此函数的设计思路)。还有其他方法可以将额外的参数传递给该函数吗? - hiro protagonist
@PythonGuy,就像主角Hiro说的那样 :)。 - Cyphase
@hiroprotagonist 哦,是的,我没有想到那个。 - user3917838

0
一个小例子,使用我能想到的最愚蠢的函数:
from functools import lru_cache

@lru_cache(maxsize=32)
def identity(x):
    return x

identity2 = lru_cache(maxsize=32)(lambda x: x)

第一个版本是装饰器版本,您可以看到lru_cache的第一个参数。从这里开始,很容易看出如何正确编写lambda表达式的语法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接