python 中若编写递归函数,为了减少计算时间,需要用到 memoize 或 memoized 功能,它们的作用是记忆函数每次运行的结果,这样当递归函数每次递归时,若已经计算过子函数,就直接从记忆中的结果获取,避免重复计算。
英文解释可以参见:
https://wiki.python.org/moin/PythonDecoratorLibrary#CA-7f0e99ea942ab4cfe29b3964877c22f84954f660_26
方法一:使用 memoized 类,代码较多
在使用这个功能时,一般在程序前面加个 memoized 的类(这个类可以直接复制别人写好的代码)就行,然后在定义递归函数时前面加上
@memoized
例如斐波那契函数,下面的例子中,没有使用 memoized 功能的计算时间为 41 秒,使用后计算时间为 0秒。
import time
import functools
import collections
class memoized(object):
'''Decorator. Caches a function's return value each time it is called.
If called later with the same arguments, the cached value is returned
(not reevaluated).
'''
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if not isinstance(args, collections.Hashable):
# uncacheable. a list, for instance.
# better to not cache than blow up.
return self.func(*args)
if args in self.cache:
return self.cache[args]
else:
value = self.func(*args)
self.cache[args] = value
return value
def __repr__(self):
'''Return the function's docstring.'''
return self.func.__doc__
def __get__(self, obj, objtype):
'''Support instance methods.'''
return functools.partial(self.__call__, obj)
def fib(n) :
if n in (0, 1):
return n
return fib(n-1)+fib(n-2)
@ memoized
def fib2(n) :
if n in (0, 1):
return n
return fib2(n-1)+fib2(n-2)
start = time.clock()
a = fib(40)
print(a)
end = time.clock()
cpu_time = end-start
print('cpu time is %.3f' % cpu_time)
start = time.clock()
b = fib2(40)
print(b)
end = time.clock()
cpu_time = end-start
print('cpu time after memoizing is %.3f' % cpu_time)
输出结果:
102334155
cpu time is 40.536
102334155
cpu time after memoizing is 0.000
方法二:使用 lru_cache(),代码更少
同样需要调用 functools 包,在定义递归函数时前面加上
@lru_cache()
括号里面可以添加数字,表示记忆的条目数量。默认数量是 128。
如果最大容量不知道多少,可以在括号里加参数 maxsixe=None
实际的算例测试时,我感觉比第一种方法快
示例:
import time
from functools import lru_cache
def fib(n) :
if n in (0, 1):
return n
return fib(n-1)+fib(n-2)
@lru_cache(1000)
def fib3(n) :
if n in (0, 1):
return n
return fib3(n-1)+fib3(n-2)
start = time.clock()
a = fib(40)
print(a)
end = time.clock()
cpu_time = end-start
print('cpu time is %.3f' % cpu_time)
start = time.clock()
b = fib3(40)
print(b)
end = time.clock()
cpu_time = end-start
print('cpu time after memoizing is %.3f' % cpu_time)
输出:
102334155
cpu time is 37.304
102334155
cpu time after memoizing is 0.000