最近在看 flask的視圖裝飾器 時,突然想起預(復)習一下python的裝飾器.html
這裏有一篇比較好的講解裝飾器的書寫的 Python裝飾器學習(九步入門) .python
這裏不單獨記錄裝飾器的書寫格式了,重點是工做流程.flask
首先常見的 裝飾器 格式就是經過@語法糖,簡便的寫法,讓流程有些不太清楚.app
裝飾器不帶參數的狀況下:函數
def deco(func): def _deco(): print("before myfunc() called.") func() print(" after myfunc() called.") return _deco @deco def myfunc(): print(" myfunc() called.") myfunc()
運行結果:學習
before myfunc() called. myfunc() called. after myfunc() called. myfunc() called.
這個@語法糖的做用是:code
def myfunc(): print(" myfunc() called.") myfunc = deco(myfunc)
也就是如今的myfunc再也不是一開始定義的那個了,而變成了orm
def _deco(): print("before myfunc() called.") func() print(" after myfunc() called.")
這一點能夠經過htm
print myfunc.__name__
而複雜一點的,裝飾器帶參數的,如:blog
def deco(arg="haha"): def _deco(func): def __deco(): print("before %s called [%s]." % (func.__name__, arg)) func() print(" after %s called [%s]." % (func.__name__, arg)) return __deco return _deco @deco()#注意有括號 def myfunc(): print(" myfunc() called.") @deco("haha1") def myfunc1(): print(" myfunc() called.") myfunc() myfunc1()
實際的操做是,先把裝飾進行了運算,即函數deco先被調用
等效於:
def _deco(func): def __deco(): print("before %s called [%s]." % (func.__name__, "haha"))# arg ==> "haha" func() print(" after %s called [%s]." % (func.__name__, "haha"))# arg ==> "haha" return __deco @d_deco#注意沒有括號,第一處 def myfunc(): print(" myfunc() called.") @_deco#這也沒括號,第二處 def myfunc1(): print(" myfunc1() called.") myfunc() myfunc1()
而參數arg 使用的是默認的"haha
更直觀的表達方式就是:
def deco(arg="haha"): def _deco(func): def __deco(): print("before %s called [%s]." % (func.__name__, arg)) func() print(" after %s called [%s]." % (func.__name__, arg)) return __deco return _deco def myfunc(): print(" myfunc() called.") def myfunc1(): print(" myfunc() called.") myfunc = deco()(myfunc) myfunc1 = deco("haha1")(myfunc1)
這時再來看標準庫functools中的wraps的使用,好比官網例子:
from functools import wraps def my_decorator(f): @wraps(f) def wrapper(*args, **kwds): print 'Calling decorated function' return f(*args, **kwds) return wrapper @my_decorator def example(): """Docstring""" print 'Called example function' example() print example.__name__ print example.__doc__
過程就是
def my_decorator(f): def wrapper(*args, **kwds): print 'Calling decorated function' return f(*args, **kwds) wrapper.__name__ = f.__name__ wrapper.__doc__ = f.__doc__ return wrapper example = my_decorator(example)
這樣就保留了原函數名稱屬性和doc,
標準庫中函數wraps,能夠這樣理解:
def wraps(f): def _f(*args,**kwargs): f(*args,**kwargs) _f.__name__ = f.__name _f.__doc__ = f.__doc__ return _f
上面的wraps流程能夠看出,若是直接使用wraps簡直就是f = f(其實不能直接使用),因此通常都是如實例這樣包藏在一個裝飾器函數內部.
注:示例代碼來自:Python裝飾器學習(九步入門) 及 python標準庫functools之wraps