被裝飾器裝飾的函數名即使沒有被調用(因為有@xxx,會觸發運行裝飾器),(裝飾器工廠函數)定義裝飾器的代碼已經運行了(最內部的那個函數並沒有運行)(把被裝飾的原函數引用賦值給了裝飾器內部的那個函數名),當下邊通過該函數名調用時,會調用到裝飾器內部的那個函數()
裝飾器:在不修改函數源代碼的基礎上,添加函數功能
一個簡單的裝飾器
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
當@裝飾器后有參數時
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
兩個裝飾器同時修飾一個函數(重點看執行順序)
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將數據返回給接受的變量或引用)
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 2
2end
1end <b><i>hello world-3</i></b> Process finished with exit code 0
