首先咱們要知道在python,一切皆對象,函數也是一個對象 python
>>> def test(): ... return "Hello World"
有本身的id值,有type,有本身的值app
>>> id(test) 140155005410568 >>> type(test) <class 'function'> >>> test <function test at 0x7f78614f9d08>
甚至能夠賦值給其餘變量函數
>>> test1 = test >>> test1() 'Hello World'
哪怕是當作參數傳遞給別的函數,也能夠當作函數的返回值網站
>>> def foo(func): ... print(func) ... return func ... >>> test2 = foo(test) <function test at 0x7f78614f9d08> >>> test2() 'Hello World'
裝飾器本質其實就是一個函數, 可讓其它函數不改動源代碼的狀況下增長其餘新功能, 好比網站常常須要的權限校驗等場景code
def add(x, y): print(x+y) add(1,2)
如今咱們有一個新需求, 計算代碼執行時間orm
import time def add(x, y): start_time = time.time print(x+y) stop_time = time.time print("{func} spend {time} ".format(func = "add", time = stop_time-start_time)) add(1,2)
咱們固然能夠這麼寫, 可是一來修改了源代碼可能會形成一些未知的錯誤, 二來若是咱們有一百個函數, 這樣寫也不現實, 這就是咱們裝飾器出場的時候了.對象
import time def timmer(func): """ :param func: 被裝飾的函數 :return: 一個計算函數運行時間的函數 """ def wrapper(*args, **kwargs): """ :param args:收集被裝飾函數的參數 :param kwargs:收集被裝飾函數的關鍵字參數 :return: """ start_time = time.time() # 讓進程睡一秒 time.sleep(1) # 調用被裝飾的函數 result = func(*args, **kwargs) stop_time = time.time() print("{func} spend {time} ".format(func = "add", time = stop_time-start_time)) return result return wrapper
def add(x, y): print(x,y) # 由於timmer返回的是wrapper函數對象,因此執行add()至關於執行wrapper() add = timmer(add) add(1,2)
@timmer def add(x, y): print(x,y) add(1,2)
這就是最基本的裝飾器, 在不修改源代碼的前提下爲函數添加一個新功能, 調用時只須要在原函數上方添加一個 @deco_name , 在這裏是@timmer進程
python還容許咱們給裝飾器帶上函數io
import time def timmer(flag): """ :param flag: 接收裝飾器的參數 :return: """ def outer_wrapper(func): """ :param func: 接收被裝飾的函數 :return: """ # 接收被裝飾函數的參數 def wrapper(*args, **kwargs): """ :param args: 收集被裝飾函數的參數 :param kwargs: 收集被裝飾函數的關鍵字參數 :return: """ if flag == "true": start_time = time.time() # 調用被裝飾的函數 result = func(*args, **kwargs) # 讓進程睡一秒 time.sleep(1) stop_time = time.time() print("{func} spend {time} ".format(func="add", time=stop_time - start_time)) return result else: print("Unexpected ending") return wrapper return outer_wrapper
所謂的語法糖即是你不使用也能夠完成任務,可是使用它可讓你的代碼更簡潔function
@timmer(flag="false") def add(x, y): print(x, y) add(1,2)
當函數被多個裝飾器裝飾時,從裏向外裝飾
@a @b @c def func(): pass
至關於
func = a(b(c(func)))