http://www.cnblogs.com/tqsummer/archive/2011/01/24/1943314.html, Python和Decorator(裝飾器)模式
http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html, Python裝飾器與面向切面編程
最近在看FP相關, 看到Closure, 想起這個... python的裝飾器方法是用閉包實現的
Closure是什麼就不解釋了, 可以看上面第一個blog
裝飾器, 經典的設計模式, 動態地給一個對象添加一些額外的職責.
大家在寫代碼的時候, 除了核心的邏輯, 往往還有許多輔助的邏輯, 比如, log, try catch, lock, time計時, 等等...
如果都混在一起, 嚴重影響代碼的整潔度, 比如log或try catch這種需要隨處加的, 非常影響開發效率, 和可讀性
而裝飾器最大的應用, 就是將核心代碼和輔助代碼分離.
以time為例,大家在測performance的時候會在自己代碼裡面加上大量的這樣的代碼, 非常煩...
import timedef foo(): start = time.clock() print 'in foo()' end = time.clock() print 'used:', end - start
Python這種動態語言, function也是first-class, 所以簡單改進如下, 雖然簡單, 但是這已經屬於裝飾器設計模式
這種改動的問題在於, 你想想這種performance代碼都是臨時加上的, 如果每次都需要修改函數名來測時間, 相當麻煩
import time def foo(): print 'in foo()' def timeit(func): start = time.clock() func() end =time.clock() print 'used:', end - start 這個例子開始, 就是使用閉包(closure)來實現裝飾器模式. 其中wrapper就是個閉包, 因為裡麵包含外部變數func
好處是, 在每個需要test的function前面, 加上一個聲明就ok, 更方便一些.
有個問題需要注意的是, 完成foo = timeit(foo)後, foo的funciton name是wrapper, 而不是foo. 如果要解決這個問題, 需要使用functools.wraps
import time def foo(): print 'in foo()' def timeit(func): def wrapper(): start = time.clock() func() end =time.clock() print 'used:', end - start return wrapper foo = timeit(foo)foo()
裝飾器方法的Python文法糖,@
@timeit,在定義上加上這一行與另外寫foo = timeit(foo)完全等價
import time def timeit(func): def wrapper(): start = time.clock() func() end =time.clock() print 'used:', end - start return wrapper @timeitdef foo(): print 'in foo()'
python中內嵌的裝飾器方法, 分別是staticmethod、classmethod和property
再給出一個lock的例子, 對於線程lock需要傳入同一個lock對象, 更加體現出閉包
博主嫌這個方法不夠優雅, 寫了套更簡單的
把lock對象的產生封裝到一個Decorate類中, 並在類初始化是完成對於所有類函數自動的wrapper, 這個取決於python的動態特性, 可以run-time時擷取, 修改函數的邏輯.
具體可以參考第一個blog
def sync(func): def wrapper(*args, **kv): self = args[0] self.lock.acquire() try: return func(*args, **kv) finally: self.lock.release() return wrapperclass Foo(object): def __init__(self, …): self.lock = threading.Lock() @sync def interface1(self, …): do something @sync def interface2(self, …): do something