在functools这个模块中,有lru_cache这个一个神奇的装饰器存在。functools.lru_cache的作用主要是用来做缓存,他能把相对耗时的函数结果进行保存,避免传入相同的参数重复计算。同时,缓存并不会无限增长,不用的缓存会被释放。
举fluent python中的例子来说:
首先实现一个计算运行时间的装饰器
import time
import functools
def clock(func):
# functools.wraps(func)装饰器的作用是将func函数的相关属性复制到clock中
# 比如说__name__, __doc__等等
@functools.wraps(func)
def clocked(*args, **kwargs):
t0 = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - t0
name = func.__name__
arg_lst = []
if args:
arg_lst.append(', '.join(repr(arg) for arg in args))
if kwargs:
pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
arg_lst.append(', '.join(pairs))
arg_str = ', '.join(arg_lst)
print('[%0.8fs] %s(%s) -> %r ' % (elapsed, name, arg_str, result))
return result
接下来写一个生成第n个斐波纳契数的函数
from clockdeco import clock
@clock
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1)
if __name__=='__main__':
print(fibonacci(6))
运行结果:
[0.00000041s] fibonacci(0) -> 0
[0.00000051s] fibonacci(1) -> 1
[0.00003454s] fibonacci(2) -> 1
[0.00000025s] fibonacci(1) -> 1
[0.00000026s] fibonacci(0) -> 0
[0.00000024s] fibonacci(1) -> 1
[0.00000743s] fibonacci(2) -> 1
[0.00001429s] fibonacci(3) -> 2
[0.00005602s] fibonacci(4) -> 3
[0.00000022s] fibonacci(1) -> 1
[0.00000023s] fibonacci(0) -> 0
[0.00000021s] fibonacci(1) -> 1
[0.00000672s] fibonacci(2) -> 1
[0.00001346s] fibonacci(3) -> 2
[0.00000021s] fibonacci(0) -> 0
[0.00000022s] fibonacci(1) -> 1
[0.00000691s] fibonacci(2) -> 1
[0.00000022s] fibonacci(1) -> 1
[0.00000027s] fibonacci(0) -> 0
[0.00000022s] fibonacci(1) -> 1
[0.00000708s] fibonacci(2) -> 1
[0.00001363s] fibonacci(3) -> 2
[0.00002687s] fibonacci(4) -> 3
[0.00004682s] fibonacci(5) -> 5
[0.00011096s] fibonacci(6) -> 8
8
有大量的重复函数计算在整个运行过程中,比如fibonacci(1),fibonacci(2)就分别运行了多次。
现在给fibonacci()函数加上@functools.lru_cache()装饰器进行缓存实现
from clockdeco import clock
@functools.lru_cache()
@clock
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1)
if __name__=='__main__':
print(fibonacci(6))
一共就多了一行代码,那看看运行结果如何。
[0.00000041s] fibonacci(0) -> 0
[0.00000054s] fibonacci(1) -> 1
[0.00004040s] fibonacci(2) -> 1
[0.00000104s] fibonacci(3) -> 2
[0.00005465s] fibonacci(4) -> 3
[0.00000072s] fibonacci(5) -> 5
[0.00006876s] fibonacci(6) -> 8
8
不使用lru_cache装饰器时的运行时间是0.00011096s,加上以后变成了0.00006876s。这个效率增加的杠杆的,尤其在充斥这大量重复计算时,它更能够为程序的运行节省大量的时间。
另外:functools.lru_cache(maxsize=128, typed=False)有两个可选参数,我们来看看他们分别代表的意义。
* maxsize代表缓存的内存占用值,超过这个值之后,就的结果就会被释放,然后将新的计算结果进行缓存,其值应当设为2的幂 *
* typed若为True,则会把不同的参数类型得到的结果分开保存 *
ps:
@functools.lru_cache()
@clock
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1)
这段代码中叠加使用了两个装饰器,那具体这两个装饰器的先后顺序是怎么样的。
举个例子:
@d1
@d2
def f():
print('f')
等于
def f():
print('f')
f = d1(d2(f))
也就是说从下往上依次执行