python裝飾器的參數傳遞


被裝飾器裝飾的函數名即使沒有被調用(因為有@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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM