functools.lru_cache装饰器

functools.lru_cache装饰器

functools.lru_cache是非常实用的装饰器,他实现了备忘功能它把耗时的函数的结果保存起来,避免传入相同的参数时重复计算。LRU是Least Recently Used的缩写,表明缓存不会无限制增长,一段时间不用的缓存条目会被扔掉。

使用递归来生成斐波那契的第n个数

# clock 装饰器
import time
import functools


def clock(func):
    @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
    return clocked


# 利用递归方式生成斐波那契
@clock
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 2) + fibonacci(n - 1)


if __name__ == '__main__':
    print(fibonacci(6))
    
'''
[0.00000000s] fibonacci(0) -> 0 
[0.00000000s] fibonacci(1) -> 1 
[0.00081015s] fibonacci(2) -> 1 
[0.00000000s] fibonacci(1) -> 1 
[0.00000000s] fibonacci(0) -> 0 
[0.00000000s] fibonacci(1) -> 1 
[0.00000000s] fibonacci(2) -> 1 
[0.00000000s] fibonacci(3) -> 2 
[0.00081015s] fibonacci(4) -> 3 
[0.00000000s] fibonacci(1) -> 1 
[0.00000000s] fibonacci(0) -> 0 
[0.00000000s] fibonacci(1) -> 1 
[0.00000000s] fibonacci(2) -> 1 
[0.00081134s] fibonacci(3) -> 2 
[0.00000000s] fibonacci(0) -> 0 
[0.00000000s] fibonacci(1) -> 1 
[0.00000000s] fibonacci(2) -> 1 
[0.00000000s] fibonacci(1) -> 1 
[0.00000000s] fibonacci(0) -> 0 
[0.00000000s] fibonacci(1) -> 1 
[0.00000000s] fibonacci(2) -> 1 
[0.00000000s] fibonacci(3) -> 2 
[0.00000000s] fibonacci(4) -> 3 
[0.00081134s] fibonacci(5) -> 5 
[0.00162148s] fibonacci(6) -> 8 
8
'''

可以看出使用递归会进行很多重复的计算,数据量增多时调用和计算更多。

使用functools.lru_cache优化

# clock 装饰器
import time
import functools


def clock(func):
    @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
    return clocked


# 利用递归方式生成斐波那契
@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.00000000s] fibonacci(0) -> 0 
[0.00000000s] fibonacci(1) -> 1 
[0.00000000s] fibonacci(2) -> 1 
[0.00000000s] fibonacci(3) -> 2 
[0.00000000s] fibonacci(4) -> 3 
[0.00000000s] fibonacci(5) -> 5 
[0.00000000s] fibonacci(6) -> 8 
8
'''

可以看到使用lru_cache性能会显著改善。需要注意的是被lru_cache装饰的函数接受的参数必须是不可变类型。

posted @ 2019-05-13 10:35  村口王铁匠  阅读(968)  评论(0编辑  收藏  举报