被裝飾器裝飾的函數名即便沒有被調用(由於有@xxx,會觸發運行裝飾器),(裝飾器工廠函數)定義裝飾器的代碼已經運行了(最內部的那個函數並無運行)(把被裝飾的原函數引用賦值給了裝飾器內部的那個函數名),當下邊經過該函數名調用時,會調用到裝飾器內部的那個函數()html
裝飾器:在不修改函數源代碼的基礎上,添加函數功能python
一個簡單的裝飾器app
def log_time(func): # 此函數的做用時接受被修飾的函數的引用test,而後被內部函數使用 def make_decorater(): print('如今開始裝飾') func() print('如今結束裝飾') return make_decorater # log_time()被調用後,運行此函數返回make_decorater()函數的引用make_decorater @log_time # 此行代碼等同於,test=log_time(test)=make_decorater def test(): print('我是被裝飾的函數') test() # test()=make_decorater()
D:\pycharm_project\裝飾器\venv\Scripts\python.exe D:/pycharm_project/裝飾器/venv/裝飾器.py 如今開始裝飾 我是被裝飾的函數 如今結束裝飾 Process finished with exit code 0
當被裝飾的函數有形參時函數
def log_time(func): def make_decorater(*args,**kwargs): # 接受調用語句的實參,在下面傳遞給被裝飾函數(原函數) print('如今開始裝飾') test_func = func(*args,**kwargs) # 若是在這裏return,則下面的代碼沒法執行,因此引用並在下面返回 print('如今結束裝飾') return test_func # 由於被裝飾函數裏有return,因此須要給調用語句(test(2))一個返回,又由於test_func = func(*args,**kwargs)已經調用了被裝飾函數,這裏就不用帶()調用了,區別在於運行順序的不一樣。 return make_decorater @log_time def test(num): print('我是被裝飾的函數') return num+1 a = test(2) # test(2)=make_decorater(2) print(a)
D:\pycharm_project\裝飾器\venv\Scripts\python.exe D:/pycharm_project/裝飾器/venv/裝飾器.py 如今開始裝飾 我是被裝飾的函數 如今結束裝飾 3 Process finished with exit code 0
當@裝飾器後有參數時code
def get_parameter(*args,**kwargs): # 工廠函數,用來接受@get_parameter('index.html/')的'index.html/' def log_time(func): def make_decorater(): print(args,kwargs) print('如今開始裝飾') func() print('如今結束裝飾') return make_decorater return log_time @get_parameter('index.html/') def test(): print('我是被裝飾的函數') # return num+1 test() # test()=make_decorater()
D:\pycharm_project\裝飾器\venv\Scripts\python.exe D:/pycharm_project/裝飾器/venv/裝飾器.py ('index.html/',) {} 如今開始裝飾 我是被裝飾的函數 如今結束裝飾 Process finished with exit code 0
兩個裝飾器同時修飾一個函數(重點看執行順序)htm
def log_time1(func): def make_decorater(*args,**kwargs): print('1如今開始裝飾') test_func = func(*args,**kwargs) print('1如今結束裝飾') return test_func return make_decorater def log_time2(func): def make_decorater(*args,**kwargs): # 接受調用語句的實參,在下面傳遞給被裝飾函數(原函數) print('2如今開始裝飾') test_func = func(*args,**kwargs) # 若是在這裏return,則下面的代碼沒法執行,因此引用並在下面返回 print('2如今結束裝飾') return test_func # 由於被裝飾函數裏有return,因此須要給調用語句(test(2))一個返回,又由於test_func = func(*args,**kwargs)已經調用了被裝飾函數,這裏就不用帶()調用了,區別在於運行順序的不一樣。 return make_decorater @log_time1 @log_time2 def test(num): print('我是被裝飾的函數') return num+1 a = test(2) # test(2)=make_decorater(2) print(a)
D:\pycharm_project\裝飾器\venv\Scripts\python.exe D:/pycharm_project/裝飾器/venv/裝飾器.py 1如今開始裝飾 2如今開始裝飾 我是被裝飾的函數 2如今結束裝飾 1如今結束裝飾 3 Process finished with exit code 0
注意看執行結果(print,只有執行就會輸出到屏幕)(return將數據返回給接受的變量或引用)blog
def makeBold(fn): def wrapped1(): print('1') b = "<b>" + fn() + "</b>" # 此行fn()調用了wrapped(),因此wrapped()執行了print輸出到屏幕,而後fn()接受到了wrapped() return返回的結果"<i>" + fn() + "</i>",因此須要等待wrapped()
print('1end') # 只有b = "<b>" + fn() + "</b>"執行完畢纔會執行這一行,只有wrapped()函數 return返回後,上一行代碼才執行
return b return wrapped1 def makeItalic(fn): def wrapped(): print('2') a = return "<i>" + fn() + "</i>" # 此行fn()調用了test3(),因此test3()執行了,而後fn()接受到了test3()中returnd返回的結果"hello world-3",因此須要等待test3
print('2end') # 當test3()返回後,上一行代碼執行完畢,在屏幕上輸出此行
return a return wrapped @makeBold @makeItalic def test3(): return "hello world-3" # return 給了wrapped,wrapped又return給了wrapped; a = test3() # 此行test3() = wrapped1(),test3()調用了函數因此裝飾器才執行。a接受了裝飾器return的結果 print(a)
D:\pycharm_project\裝飾器\venv\Scripts\python.exe D:/pycharm_project/裝飾器/venv/text.py 1 22end1end <b><i>hello world-3</i></b> Process finished with exit code 0