本文案例內容參考自:https://www.liaoxuefeng.com/wiki/1016959663602400/1017451662295584
裝飾器概念
當我們想爲現有的函數增加額外功能,但又不想改變這個函數內部的代碼,那麼我們可以通過爲該函數添加“裝飾器”的形式來實現額外功能。
裝飾器簡例
例如目前我們現在有一個打印時間字符串的函數:
def timestr():
print("2020-06-03")
當我們執行時,該函數只會打印一個時間字符串,現在我們想在執行該函數時可以額外打印該函數的名字,便可以定義如下“裝飾器”函數:
def log(func):
def wrapper(*args,**kw):
print(f"func name is {func.__name__}")
return func(*args,**kw)
return wrapper
定義完裝飾器,使用裝飾器的格式如下:
@log
def timestr():
print("2020-06-03")
這樣,當我們直接執行 timestr() 時,便會得到如下結果:
func name is timestr
2020-06-03
裝飾器在這裏就實現了打印函數名稱的額外功能。這裏 @log 相當於執行了 timestr = log(timestr),此時如果再打印修飾器修飾過的 timestr 函數名稱,會發現其變成了 wrapper:
print(timestr.__name__)
# 'wrapper'
這就需要把原始函數的名稱等屬性同步複製到 wrapper() 函數中,否則有些依賴函數簽名的代碼執行就會出錯。
這裏就需要 Python 內置的 functools.wraps 來實現同步相關屬性,最終裝飾器完整版代碼如下:
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args,**kw):
print(f"func name is {func.__name__}")
return func(*args,**kw)
return wrapper
@log
def timestr():
print("2020-06-03")
這樣再次打印 timestr 的函數名時,就會同步爲原函數名 ‘timestr’。