閱讀333 返回首頁    go 技術社區[雲棲]


Python裝飾器學習

在《Core Python Programming 2nd》中學習到了裝飾器,這對我來說是個完全陌生的語法,第一遍愣是沒看懂,很有必要記一下。

 

第一眼看到這個詞Decorator,我聯想到了DP中的Decorator模式,後來才知道完全不是這麼一回事。(再次鄙視一下國內浮躁的博客,我google了一下,幾乎千篇一律都是什麼鎖同步裝飾器、超時裝飾器,我對原作者表達敬仰,可是大家都是轉載就不像話了,也是對網絡資源的極大浪費,也許真正有價值的博文就湮沒在這片都是一模一樣的東西裏了)

 

1. 這是個什麼東東?
書上說得不是太清楚,它說類似於Java的AOP(Aspect Oriented Programming,麵向方麵編程),我對AOP一無所知。根據我對許多例子用法的反複揣摩,我認為是類似於程序設計語義學中所說的前鍵後鍵 的概念(Eiffel中的@pre@post )。當然你可以在裝飾器中做比前鍵與後鍵更多的事,如:引入日誌、增加計時邏輯來檢測性能、給函數增加事務的能力。

 

其實總體說起來,裝飾器其實也就是一個函數,一個用來包裝函數的函數,返回一個修改之後的函數對象,將其重新賦值原來的標識符,並永久喪失對原始函數對象的訪問。

 

2. 裝飾器語法

(1)無參數裝飾器

  1. def deco(func):  
  2.     print func  
  3.     return func  
  4. @deco  
  5. def foo():pass  
  6. foo()  
def deco(func): print func return func @deco def foo():pass foo()

第一個函數deco是裝飾函數,它的參數就是被裝飾的函數對象。我們可以在deco函數內對傳入的函數對象做一番“裝飾”,然後返回這個對象(記住一定要返回 ,不然外麵調用foo的地方將會無函數可用。實際上此時foo=deco(foo))

 

我寫了個小例子,檢查函數有沒有說明文檔:

  1. def deco_functionNeedDoc(func):  
  2.     if func.__doc__ == None :  
  3.         print func, "has no __doc__, it's a bad habit."  
  4.     else:  
  5.         print func, ':', func.__doc__, '.'  
  6.     return func  
  7. @deco_functionNeedDoc  
  8. def f():  
  9.     print 'f() Do something' 
  10. @deco_functionNeedDoc  
  11. def g():  
  12.     'I have a __doc__'  
  13.     print 'g() Do something'  
  14. f()  
  15. g()  
def deco_functionNeedDoc(func): if func.__doc__ == None : print func, "has no __doc__, it's a bad habit." else: print func, ':', func.__doc__, '.' return func @deco_functionNeedDoc def f(): print 'f() Do something' @deco_functionNeedDoc def g(): 'I have a __doc__' print 'g() Do something' f() g()

 

(2)有參數裝飾器

  1. def decomaker(arg):  
  2.     '通常對arg會有一定的要求'  
  3.     """由於有參數的decorator函數在調用時隻會使用應用時的參數  
  4.        而不接收被裝飾的函數做為參數,所以必須在其內部再創建  
  5.        一個函數  
  6.     """  
  7.     def newDeco(func):    #定義一個新的decorator函數  
  8.         print func, arg  
  9.         return func  
  10.     return newDeco  
  11. @decomaker(deco_args)  
  12. def foo():pass  
  13. foo()  
def decomaker(arg): '通常對arg會有一定的要求' """由於有參數的decorator函數在調用時隻會使用應用時的參數 而不接收被裝飾的函數做為參數,所以必須在其內部再創建 一個函數 """ def newDeco(func): #定義一個新的decorator函數 print func, arg return func return newDeco @decomaker(deco_args) def foo():pass foo()

第一個函數decomaker是裝飾函數,它的參數是用來加強“加強裝飾”的。由於此函數並非被裝飾的函數對象,所以在內部必須至少創建一個接受被裝飾函數的函數,然後返回這個對象(實際上此時foo=decomaker(arg)(foo))

 

這個我還真想不出什麼好例子,還是見識少啊,隻好借用同步鎖的例子了:

  1. def synchronized(lock):  
  2.     """鎖同步裝飾方法 
  3.     !lock必須實現了acquire和release方法 
  4.     """  
  5.     def sync_with_lock(func):  
  6.         def new_func(*args, **kwargs):  
  7.             lock.acquire()  
  8.             try:  
  9.                 return func(*args, **kwargs)  
  10.             finally:  
  11.                 lock.release()  
  12.         new_func.func_name = func.func_name  
  13.         new_func.__doc__ = func.__doc__  
  14.         return new_func  
  15.     return sync_with_lock  
  16. @synchronized(__locker)  
  17. def update(data):  
  18. """更新計劃任務"""  
  19.     tasks = self.get_tasks()  
  20.     delete_task = None  
  21.     for task in tasks:  
  22.         if task[PLANTASK.ID] == data[PLANTASK.ID]:  
  23.             tasks.insert(tasks.index(task), data)  
  24.             tasks.remove(task)  
  25.             delete_task = task  
  26.     r, msg = self._refresh(tasks, delete_task)  
  27.     return r, msg, data[PLANTASK.ID]  
def synchronized(lock): """鎖同步裝飾方法 !lock必須實現了acquire和release方法 """ def sync_with_lock(func): def new_func(*args, **kwargs): lock.acquire() try: return func(*args, **kwargs) finally: lock.release() new_func.func_name = func.func_name new_func.__doc__ = func.__doc__ return new_func return sync_with_lock @synchronized(__locker) def update(data): """更新計劃任務""" tasks = self.get_tasks() delete_task = None for task in tasks: if task[PLANTASK.ID] == data[PLANTASK.ID]: tasks.insert(tasks.index(task), data) tasks.remove(task) delete_task = task r, msg = self._refresh(tasks, delete_task) return r, msg, data[PLANTASK.ID]

調用時還是updae(data)。

 

同時還可以將多個裝飾器組合 使用:

  1. @synchronized(__locker)  
  2. @deco_functionNeedDoc  
  3. def f():  
  4.     print 'f() Do something'  
@synchronized(__locker) @deco_functionNeedDoc def f(): print 'f() Do something'

學後的總是感覺就是:裝飾器可以讓函數輕裝上陣,更重要的是將函數的約束放置於接口處,使意圖更加明了,同時又不增加調用者的負擔。

最後更新:2017-04-02 22:16:23

  上一篇:go js數組操作大全
  下一篇:go HTTP協議詳解