lru_cache singledispatch 2個標準庫的裝飾器
阿新 • • 發佈:2018-11-10
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)