裝飾器
裝飾器本質上是一個函數,該函數用來處理其他函數,它可以讓其他函數在不需要修改代碼的前提下增加額外的功能。裝飾器的返回值也是一個函數對象,它經常用於有切面需求的場景,比如:插入日誌、性能測試、事物處理、緩存、權限校驗等應用場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量於函數功能本身無關的雷同代碼繼續重用。概括的講,裝飾器的作用就是爲已經存在的對象添加額外的功能。
一個裝飾器可以用來裝飾多個函數,一個函數也可以被多個裝飾器裝飾 。
@符號是裝飾器的語法糖,在定義函數的時候使用,避免再一次賦值操作。
無參裝飾器
它是一個函數,被裝飾函數作爲它的形參,返回值也是一個函數,使用@functionname方式調用。裝飾器是高階函數,裝飾器是對傳入函數的功能的裝飾(增強),不侵入任何代碼。
def logger(fn):
def wrapper(*args, **kwargs):
print("args={}, kwargs={}".format(args,kwargs))
ret = fn(*args, **kwargs)
print("{}".format(fn.__name__))
return ret
return wrapper
@logger # add = logger(add),返回內層函數的引用
def add(x, y):
return x + y
print(add(4,5))
帶參裝飾器
帶參裝飾器是在裝飾器外層又加了一層函數
def logger(*paras):
def _logger(fn):
def wrapper(*args, **kwargs):
print("args={}, kwargs={}".format(args,kwargs))
ret = fn(*args, **kwargs)
print("paras={}".format(paras))
print("{}".format(fn.__name__))
return ret
return wrapper
return _logger
@logger(10,20,30) # add = logger(add),返回內層函數的引用
def add(x, y):
return x + y
print(add(4,5))
functools模塊
被裝飾後的函數其實已經是另外一個函數了(函數名等函數屬性會發生改變)。爲了不影響,Python的functools包中提供了一個叫wraps的decorator來消除這樣的副作用。寫一個decorator的時候,最好在實現之前加上functools的wraps或者update_wrapper,它能保留原有函數的一些內置屬性,,例如:__name__、 __module__ 、__doc__ 和__dict__等。
import functools
def logger(fn):
# 方法一
@functools.wraps(fn)
def wrapper(*args, **kwargs):
print("args={}, kwargs={}".format(args,kwargs))
print(id(fn))
ret = fn(*args, **kwargs)
print("{}".format(fn.__name__))
return ret
# 方法二
# functools.update_wrapper(wrapper, fn)
return wrapper
@logger # add = logger(add),返回內層函數的引用
def add(x, y):
return x + y
print(add(4,5))
print(add.__name__)
print(id(add.__wrapped__))