python 裝飾器及標準庫functools中的wraps

最近在看 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

相關文章
相關標籤/搜索