Python函数对象有一个名为func_dict
的属性字典,它从函数外部可见并且是可变的,但在调用函数时不会被修改。 (我从昨天问过的问题(#1753232)的答案中学到了这一点:谢谢!)我正在阅读代码(http://pythonprogramming.jottit.com/functional_programming),该代码记住斐波纳契数的计算并思考,“为什么不使用{{1 memoizing的属性?“它起作用了(见下文;代码末尾的输出)。这有点像有一个类属性,但在对象外面有初始化代码(在这种情况下,不是类而是函数)。
我想知道使用此属性可以使用哪些类似(或不同)的技巧?
func_dict
答案 0 :(得分:7)
要小心:fib.cache
技巧只有在fib
确实是在执行时活动范围内的相关功能对象的名称时才有效(例如,当你装饰它时完成后,您必须将缓存的起始值分配给装饰器包装器,而不是装饰函数 - 如果在此之后进一步修饰,则事情会中断。)
与标准的记忆习语相比,这有点脆弱:
def fib(n, _memo={0:1, 1:1}):
if n in _memo:
return _memo[n]
else:
_memo[n] = fib(n-1) + fib(n-2)
return _memo[n]
或装饰者等效物。标准成语也更快(虽然不是很多) - 将它们放在mem.py下的名称fib1(.cache-trick one,没有打印和未修饰)和fib2(我的版本)下,我们看到...:< / p>
$ python -mtimeit -s'import mem' 'mem.fib1(20)'
1000000 loops, best of 3: 0.754 usec per loop
$ python -mtimeit -s'import mem' 'mem.fib2(20)'
1000000 loops, best of 3: 0.507 usec per loop
所以标准惯用语版本节省了大约33%的时间,但是几乎所有的调用都实际上达到了memoization缓存(在这百万个循环中的第一个之后填充) - fib2的速度优势更小缓存未命中,因为它来自访问_memo
(局部变量)vs fib.cache
(全局名称,fib,然后是其属性,缓存)的更高速度,缓存访问在缓存上占主导地位命中(没有别的;-)但是在缓存未命中时还有一些额外的工作(两个函数相同)。
无论如何,并不意味着在你的游行中下雨,但是当你发现一些新的酷想法时,一定要根据“做事的好方法”来衡量它,无论是在“稳健性”还是表现方面(如果你正在缓存,大概是你关心关于表现; - )。
答案 1 :(得分:1)
我一直用this technique进行记忆。它使用的事实是你可以调用一个不是函数的对象,只要该对象定义了__call__
方法。无论出于什么原因,无论是落后的方法,还是Alex Martelli甚至都没有出现在我身上。我猜测它的性能大致与降落的方式相同,因为它的工作方式大致相同。也许有点慢。但正如链接页面指出的那样,“fib()的定义现在是”明显的“,没有缓存代码模糊算法”这很好。