Python中的@操作符稱之為裝飾器decorator['d?k?ret?]
抠藕,它用來改變函數(shù)饿肺、方法或類的功能,但又不直接修改它們的代碼盾似,就像錦上添花敬辣,增加新功能,添花但不用去重新織錦零院,所以叫做裝飾器溉跃。
- 什么是裝飾器@decorator?
- 參數(shù)怎么通過裝飾器傳遞 args,*kargs告抄?
- 帶參數(shù)的裝飾器是怎么回事@decorator(x=3)撰茎?
- 類裝飾器怎么用class decorator?
基本裝飾器
Python中的每個(gè)東西都是對(duì)象打洼,函數(shù)也是個(gè)對(duì)象龄糊,既然是對(duì)象自然就能作為參數(shù)傳遞,也能作為結(jié)果返回募疮,比如:
def decorator(func): #裝飾函數(shù)炫惩,沒有額外功能
return func
def div(a, b): #除法函數(shù)
return a / b
chufa = decorator(div) #把div函數(shù)裝飾一下,功能不變
chufa(10, 5)
這個(gè)代碼輸出2.0阿浓。
Python的函數(shù)內(nèi)可以嵌套函數(shù)他嚷,我們把上面代碼修改一下:
def decorator(func): #裝飾函數(shù),沒有額外功能
def wrapper(a, b): #包裹函數(shù),把被除數(shù)放大10倍
a = a * 10
return func(a,b)
return wrapper
def div(a, b): #除法函數(shù)
return a / b
chufa = decorator(div) #把div函數(shù)裝飾一下筋蓖,功能不變
chufa(10, 5)
這個(gè)代碼會(huì)輸出20.0.
它的執(zhí)行順序如下圖:
好了卸耘,我們來把它改為@裝飾器的寫法:
def decorator(func): #裝飾函數(shù),沒有額外功能
def wrapper(a, b): #包裹函數(shù)扭勉,把被除數(shù)放大10倍
a = a * 10
return func(a, b)
return wrapper
@decorator #這句話相當(dāng)于div=decorator(div)
def div(a, b): #除法函數(shù)
return a / b
div(10, 5)
輸出結(jié)果仍然是20.0.@decorator
這句話就相當(dāng)于div=decorator(div)
鹊奖,和上面使用的chufa = decorator(div)
是一樣的苛聘,div
函數(shù)自身被裝飾了并且覆蓋了原來的div
函數(shù)涂炎。
所以我們可以說
@hanshu_A
def hanshu_B(...):
...
就是hanshu_B=hanshu_A(hanshu_B)
,B變?yōu)楸籄裝飾之后的函數(shù)设哗,需要注意的是hanshu_A
應(yīng)該接受一個(gè)函數(shù)作為參數(shù)唱捣,并返回一個(gè)函數(shù)作為結(jié)果。
原函數(shù)的參數(shù)
上面例子里wrapper函數(shù)使用了a,b兩個(gè)參數(shù)网梢,為了讓裝飾器函數(shù)decorator
更通用震缭,可以使用*args表示任意多個(gè)參數(shù)列表如(1,2,3,4)
,或者**args表示任意字典對(duì)象參數(shù)如(a=1,b=2,c=3)
。
修改代碼如下:
def decorator(func): #裝飾函數(shù)战虏,沒有額外功能
def wrapper(*args): #包裹函數(shù)拣宰,把被除數(shù)放大10倍
return func(args[0]*10,args[1])
return wrapper
@decorator #這句話相當(dāng)于div=decorator(div)
def div(a, b): #除法函數(shù)
return a / b
div(10, 5)
或者:
def decorator(func): #裝飾函數(shù),沒有額外功能
def wrapper(**kargs): #包裹函數(shù)烦感,把被除數(shù)放大10倍
return func(kargs['a'] * 10, kargs['b'])
return wrapper
@decorator #這句話相當(dāng)于div=decorator(div)
def div(a, b): #除法函數(shù)
return a / b
div(a=10, b=5)
也可以兩個(gè)連用巡社,保持參數(shù)原封不變傳遞:
def decorator(func): #裝飾函數(shù),沒有額外功能
def wrapper(*args, **kargs): #包裹函數(shù)手趣,把被除數(shù)放大10倍
print('do nothing...')
return func(*args, **kargs)
return wrapper
@decorator #這句話相當(dāng)于div=decorator(div)
def div(a, b): #除法函數(shù)
return a / b
div(a=10, b=5)
@decorator(x=3)帶參數(shù)的裝飾器
簡單說晌该,
@decorator(x=3)
def func(...):
...
就是func=decorator(x=3)(func)
,這時(shí)候`decorator(x=3)就要返回一個(gè)裝飾器才行绿渣,例如下面將add加法函數(shù)的參數(shù)放大100倍的代碼:
def decorator_big(n):
def decorator(func): #裝飾函數(shù)朝群,沒有額外功能
def wrapper(*args): #包裹函數(shù),把被除數(shù)放大10倍
return func(*[x * n for x in args])
return wrapper
return decorator
@decorator_big(n=100) #這句話相當(dāng)于div=decorator(div)
def add(a, b): #除法函數(shù)
return a + b
add(10, 5)
輸出[1000,500],1500
類裝飾器
類裝飾器需要定義__init__
和__call__
兩個(gè)方法中符,如下:
class my_decorator(object):
func=None
def __init__(self, f):
print("inside my_decorator.__init__()")
self.func=f
def __call__(self,*args):
print("inside my_decorator.__call__()")
self.func()
@my_decorator
def aFunction():
print("inside aFunction()")
print('-----')
aFunction()
輸出結(jié)果:
inside my_decorator.__init__()
-----
inside my_decorator.__call__()
inside aFunction()
從這里可以看出
@my_decorator
def aFunction():
...
就是aFunction=my_decorator(aFunction)
姜胖,和上面的函數(shù)裝飾器一樣思路,更多內(nèi)容需要讀者多多體會(huì)了淀散。
每個(gè)人的智能新時(shí)代
如果您發(fā)現(xiàn)文章錯(cuò)誤,請(qǐng)不吝留言指正吧凉;
如果您覺得有用隧出,請(qǐng)點(diǎn)喜歡;
如果您覺得很有用阀捅,歡迎轉(zhuǎn)載~
END