1. 程式人生 > >lru_cache singledispatch 2個標準庫的裝飾器

lru_cache singledispatch 2個標準庫的裝飾器

 

 

lru_cache  : 緩衝裝飾器, 實際上自己可以用dict 來實現 .

singledispatch  : 相當於 c++ 中 stl 的函式特化(具體例項化) .  

如果有興趣學c++ stl ,這裡是我寫的函式模版 : 函式模版 特化 模版指標 以及 類模版 具體化 特化 部分特化 友元

 

一個例子說明 lru_cache:


#一個普通裝飾器
def clock(func):
    @functools.wraps(func)  #把原函式的__doc__ 以及 __name__ 複製進來
    def clocked(*args, **kwargs):
        '''clocked'''
        start  = time.perf_counter()
        res = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        name = func.__name__
        arg_str = ','.join(repr(arg) for arg in args)
        print("elapsed [%0.8fs] %s(%s) %s: " % (elapsed , name,arg_str,res))
        return res
    return clocked



#maxsize 儲存多少條記錄 , typed 把不同的型別區分
@functools.lru_cache(maxsize=128,typed=True) #可以把這行註釋掉看看
@clock #裝飾一下
def fibo(n):
    if n < 2:
        return n
    return fibo(n-2) + fibo(n-1)

if __name__ == "__main__":
    fibo(8)

#輸出: 用了functools.lru_cache 後
elapsed [0.00000064s] fibo(0) 0: 
elapsed [0.00000064s] fibo(1) 1: 
elapsed [0.00005322s] fibo(2) 1: 
elapsed [0.00000096s] fibo(3) 2: 
elapsed [0.00007662s] fibo(4) 3: 
elapsed [0.00000096s] fibo(5) 5: 
elapsed [0.00009906s] fibo(6) 8: 
elapsed [0.00000096s] fibo(7) 13: 
elapsed [0.00012182s] fibo(8) 21: 

 

 

singledispatch  :  根據型別來呼叫某個函式實現 .

簡單來說 c++ 的模版是一種通用型別,  跟某個具體型別( int , str ....) 沒關係. 

一個c++的例子 : 

如果沒學過stl的話, 請無視這些奇怪的東西, 只需要你專注 T 就行了.
T 代表某一種資料型別, 比方說 int , double ......

template <typename T> 
T compare(const T & a, const T & b)
{
    if(a >=b)
        return a;
    return b;
}

強調一下, 請無視這些 const(只讀) 啊, &(引用) 這類符號 . python 都是引用.

現在比方說 你呼叫了 compare( 1, 2) 

此時編譯器根據引數型別 int 將給你生成一個函式 int compare(const int&,const int&)

如果 : compare( 1.0 , 2.0 )  生成 double compare(const double&,const double&)

請注意.函式內部都不會改變


那麼現在問題來了, 如果要進行字串比較, 就不能使用這樣的方式了把.

有一個東西叫特化(具體例項化):

//字串比較 , 再次請無視這些引數,我知道很醜,很難看懂.總之這是一個字串比較的特化版本

template <>  // <> 意味著特化
const char * compare(const char * const &a, const char * const & b)
{
    return strcmp(a,b);
}



現在當你使用 
const char * p1 = "123";
const char * p2 = "456";
compare(p1,p2); // 呼叫 compare(const char* const &,const char* const &);

 



#比方說有那麼一個函式 . 需要根據型別來輸出具體的情況,那麼下面是一種實現
#這種方式比較方便,但難以維護 . 有可能上百個情況
def print_type(obj):
    if isinstance(obj,int):     #每次都用 isinstance 來判斷
        print("int")
    elif isinstance(obj,str):
        print("str")
    else:
        print("other")





#下面是singledispatch
#特殊處理的函式名 我這裡都是 _ , 請隨意吧
#總的來說就是 根據不同的型別來呼叫不同的函式



@functools.singledispatch  #裝飾之後,這個相當於一個模版了
def print_type2(obj):
    print("原始版本 type:%s" %type(obj))


@print_type2.register(str)  #特殊處理 str ,如果 obj 是str 將呼叫這個函式, 相當於c++的特化
def _(text):
    print("im str : %s , text:%s"  % (type(text),text))



@print_type2.register(int)  #處理 int的版本, 如果obj 是 int 呼叫此函式
def _(n):
    print("im int: %s , n:%s" % (type(n), n))


if __name__ == "__main__":
    print_type2(1)   #將呼叫_(n)