functools.lru_cache装饰器详解

在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))

也就是说从下往上依次执行

你可能感兴趣的:(------【Python】,★语言)