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裝飾的函數接受的參數必須是不可變類型。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM