As we know,裝飾器的作用是在不改變原函數邏輯和調用方式的情況下為函數附加新的功能。
def hello():
print('hello world!')
return 1
一個非常簡單的函數,現在在輸出hello world!之前輸出星号,在輸出hello world!之後輸出等号,裝飾器如下
def deco():
def inner(func):
print('*'*12)
func()
print('='*12)
return inner
原函數使用裝飾器
@deco
def hello():
print('hello world!')
return 1
調用函數即可看到如下輸出

使用@符号相當于執行了以下兩步
hello = deco(hello)
hello()
函數也是一個對象,可以當作參數傳遞給其它函數,第一步把hello當作參數傳遞給deco函數,deco傳回inner函數,然後在把inner函數指派給hello,這樣的話再次調用hello的時候其實執行的是inner的邏輯,由于把原hello函數當作參數傳遞給了inner,是以在inner内調用原函數即可。
但是,這樣的裝飾器是有問題的
原函數傳回值
原函數是有傳回值的,但是經過裝飾器調用之後把inner指派給了原函數,然而inner無傳回值,這就尴尬了,是以要讓inner傳回原函數的傳回值
def deco(func):
def inner():
print('*' * 12)
ret = func() # 接收原函數傳回值
print('=' * 12)
return ret
return inner
傳回值問題解決了,但是,函數名卻變了
函數名問題
沒使用裝飾器的時候
print(hello.__name__) # 輸出hello
使用裝飾器後
@deco
def hello():
pass
print(hello.__name__) # 輸出inner
函數名變了,好像也不太對~
解決這個問題,使用内置子產品functools改造裝飾器
def deco(func):
@functools.wraps(func)
def inner():
ret = func()
return ret
return inner
這樣的裝飾器隻能用于沒有參數的函數,對于有參數的函數怎麼搞?
函數參數
def deco(func):
@functools.wraps(func)
def inner(*args, **kwargs):
ret = func(*args, **kwargs)
return ret
return inner
因為給函數使用裝飾器後,原函數其實就變成了裝飾器的内部函數,那麼原函數的參數就是傳遞給裝飾器的内部函數,裝飾器的内部函數就要能夠接收參數
給裝飾器指定參數
def deco_params(*arg, **kw):
def deco(func):
@functools.wraps(func)
def inner(*args, **kwargs):
ret = func(*args, **kwargs)
return ret
return inner
return deco
使用裝飾器
@deco_params(1, 2)
def hello(a, b):
pass
調用過程
deco = deco_params(1, 2)
hello = deco(hello)
hello(3, 4)