1. 程式人生 > 實用技巧 >20210111-2 裝飾器之案例剖析1

20210111-2 裝飾器之案例剖析1

高階函式
   a: 把一個函式名當做實參傳給另外一個函式(在不修改被裝飾函式原始碼的情況下為其新增功能)
   b: 返回值中包含函式名(不修改函式的呼叫方式)
# 現在寫一個裝飾器
# 兩個函式都有自己的邏輯,能夠實現自己的功能
# 寫一個裝飾器,統計函式執行時間
1-1
import time

def test1():
    time.sleep(3)
    print('in the test1')

def test2():
    time.sleep(3)
    print('in the test2')

# 統計test1 和 test2 的執行時間,但是前提是不能修改呼叫方式
1-1-1
# 如何不修改原始碼,給 test1 新增一個功能?
import time
def test1():
    time.sleep(3)
    print('in the test1')

def test2():
    time.sleep(3)
    print('in the test2')

# 寫一個高階函式
def deco(func):
    start_time = time.time()
    func()
    stop_time = time.time()
    print("the func run time  is %s" %(stop_time-start_time))

# 那麼怎麼用? # 為什麼 test1 不加括號,因為test1(),傳入的是返回值結果 deco(test1) deco(test2) ---> in the test1 the func run time is 3.0043373107910156 in the test2 the func run time is 3.0002830028533936
1-1-2
# 1-1-1 修改了函式的呼叫方式
# 如何不修改函式的呼叫方式?
# 第二類高階函式,不改變函式的呼叫方式,在使用的時候就是 test1 = deco(test1) 這種方式
# 但是前提是 需要把函式修改成 用 return 返回函式名的 第二種形式的高階函式
# 這樣,test1 就可以獲取 deco 的返回值,deco 的返回值就是 test1 的 記憶體地址
# test1() 可以正常呼叫,test2()也可以
def deco(func): start_time = time.time() return func stop_time = time.time() print("the func run time is %s" %(stop_time-start_time)) import time def test1(): time.sleep(3) print('in the test1') def test2(): time.sleep(3) print('in the test2') test1 = deco(test1) test1() test2 = deco(test2) test2() ---> in the test1 in the test2 # 沒有修改函式的呼叫方式,也沒有新增功能,什麼都沒有做 # 為什麼是這樣呢? # 因為 deco 中的 return,直接呼叫了 test1;之後的內容不會執行,這就是 return 的一個特性
1-1-3
# 因為 1-1-2 中一直在用高階函式,漏掉了巢狀
# 可以引入巢狀函式
def deco(func):
    start_time = time.time()
    return func
    stop_time = time.time()
    print("the func run time  is %s" %(stop_time-start_time))

def timer():
    def deco():
        pass
# 這是巢狀函式,如何把這個函式,融入到上面的 deco中呢?
1-1-4
import time
def timer(func):    # timer(test1)  把 test1 的記憶體地址 傳給 func = test1
    def deco():
        start_time = time.time()
        func()
        stop_time = time.time()
        print("the func run time  is %s" %(stop_time-start_time))    
    return deco     # 返回 deco 函式的記憶體地址
# 這麼做以後,用到了高階函式,用到了函式巢狀

def test1():
    time.sleep(3)
    print('in the test1')

def test2():
    time.sleep(3)
    print('in the test2')

timer(test1)
print(timer(test1))     # 返回 deco 的記憶體地址
--->
<function timer.<locals>.deco at 0x000002C818B1D558>
1-2
# 想要呼叫 timer(test1) 應該怎麼做?
# 給它賦值,然後 test1 執行就可以
import time
def timer(func):    # timer(test1)  把 test1 的記憶體地址 傳給 func = test1
    def deco():
        start_time = time.time()
        func()      # run test1()
        stop_time = time.time()
        print("the func run time  is %s" %(stop_time-start_time))    
    return deco     # 返回 deco 函式的記憶體地址
# 這麼做以後,用到了高階函式,用到了函式巢狀

def test1():
    time.sleep(3)
    print('in the test1')

def test2():
    time.sleep(3)
    print('in the test2')

test1=timer(test1)
test1()     
# 這時候,test1 執行,實際上是在執行 deco 函式,因為 timer 返回的是 deco;deco做的事情是計算時間; func 的值是 test1 的值 ---> in the test1 the func run time is 3.000483751296997 # 成功加了一個新功能,沒有改變原始碼和呼叫方式; # 用到函式的巢狀,引用高階函式的定義,最終實現這樣的效果
1-3
# 但是 1-2 那樣
# test1=timer(test1)
# test1()
# 這種方式,有些麻煩;每次都需要執行裝飾器,執行一個和原來函式名一樣的東西
# 如何直接 test1() 執行呢?
# 直譯器提供了一種語法,直接加 @timer;@ 後加上裝飾器的名字;寫在想要新增功能的函式的頭部
# @timer 就等同於 test1 = timer(test1) 這部操作
import time
def timer(func):    
    def deco():
        start_time = time.time()
        func()      
        stop_time = time.time()
        print("the func run time  is %s" %(stop_time-start_time))    
    return deco     

@timer
def test1():
    time.sleep(3)
    print('in the test1')

@timer
def test2():
    time.sleep(3)
    print('in the test2')

test1() 
test2()
--->
in the test1
the func run time  is 3.000530958175659
in the test2
the func run time  is 3.000612497329712
# 這兩個函式正常運行了,同時加上了新功能