對於某個函數,若是但願在不改變函數代碼的前提下,爲該函數增長額外的功能,
那麼能夠使用裝飾器來裝飾該函數。閉包
裝飾器是一個函數,裝飾器接收一個函數做爲參數(傳入的實參是被裝飾的函數),
裝飾器的內部嵌套定義另外一個函數,內函數中會引用裝飾器的參數,而且裝飾器的返回值是內函數。
這樣構成了一個閉包。app
爲了讓內函數接收任意類型的參數,將內函數的形參定義爲(*args, **kwargs)。
在函數中首選完成爲被裝飾函數添加新功能,而後調用被裝飾的函數。函數
裝飾器的應用語法:
在被裝飾函數的前面添加:"@裝飾器的函數名"。spa
●爲add函數添加log功能。code
#執行流程:
1,被裝飾的函數add做爲實參傳遞給裝飾器log。
2,返回裝飾器的內函數wrapper。
3,將內函數wrapper賦值給名爲add(被裝飾函數的函數名)的變量。
4,再調用被裝飾函數add時,其實調用的是裝飾器的內函數wrapper。blog
1 #add函數的裝飾器函數。 2 def log(func): 3 def wrapper(*args, **kwargs): 4 print("函數%s被調用了" % func.__name__) 5 return func(*args, **kwargs) 6 return wrapper 7 8 #添加標記@log,對函數add應用裝飾器。至關於調用了add = log(add) 9 @log 10 def add(sum1, sum2): 11 print(sum1, sum2) 12 return sum1 + sum2 13 14 #調用方法和一般同樣。打印調用結果。 15 print(add(1, 2)) 16 17 #打印實際被調用的函數名。 18 print(add.__name__) #結果爲wrapper。
●實現被裝飾後,函數名依舊是add。class
在裝飾器的內函數前面添加另一個裝飾器:@functools.wraps(裝飾器的函數名),
functools.wraps爲標準庫模塊functools中的函數wraps。import
1 import functools 2 3 def log2(func): 4 @functools.wraps(func) 5 def wrapper(*args, **kwargs): 6 print("函數%s被調用了" % func.__name__) 7 return func(*args, **kwargs) 8 return wrapper 9 10 @log2 11 def add2(sum1, sum2): 12 print(sum1, sum2) 13 return sum1 + sum2 14 15 print(add2(1, 2)) 16 17 print(add2.__name__) #結果爲add2。
●給裝飾器傳遞額外參數。
須要3層嵌套裝飾器。
對於@log3('6月','18日'),至關於執行語句:add3 = log3('6月','18日')(add3)。變量
1 def log3(month, day): 2 def decorator(func): 3 @functools.wraps(func) 4 def wrapper(*args, **kwargs): 5 print("%s%s, 函數%s被調用了" % (month, day, func.__name__)) 6 return func(*args, **kwargs) 7 return wrapper 8 return decorator 9 10 @log3('6月', '18日') 11 def add3(sum1, sum2): 12 print(sum1, sum2) 13 return sum1 + sum2 14 15 print(add3(1, 2))