20210111-2 裝飾器之案例剖析1
阿新 • • 發佈:2021-01-11
高階函式
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 # 這兩個函式正常運行了,同時加上了新功能