20210111 裝飾器之案例剖析

高階函數
a: 把一個函數名當作實參傳給另一個函數(在不修改被裝飾函數源代碼的狀況下爲其添加功能)
b: 返回值中包含函數名(不修改函數的調用方式)ide

# 如今寫一個裝飾器
# 兩個函數都有本身的邏輯,可以實現本身的功能
# 寫一個裝飾器,統計函數運行時間
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
# 這兩個函數正常運行了,同時加上了新功能
1-1
# 若是 test2 裏面有一個參數
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(name):
    print("test2:",name)

test1() 
test2()
--->
TypeError: test2() missing 1 required positional argument: 'name'
# 結果是出錯的,test2 缺乏位置參數 name
# @timer 至關於 test2 = timer(test2) 
# test2 傳到裏面都作了什麼? test2 → func → 執行 deco 因此,內嵌的deco函數,執行了嗎?
# return deco,直接返回了 deco 的內存地址
# test2 實際上是等於 deco,因而 test2()至關於 deco(),執行到 func()時,至關於執行到了 test2()
# 可是 test2 是要求傳參數的,test2()沒有傳參;因此會報錯
# 那麼,這種狀況應該如何處理?如何把參數傳進來?
1-2
# test2(name),其實就是至關於 deco(name)
import time
def timer(func):    
    def deco(arg1):
        start_time = time.time()
        func(arg1)      
        stop_time = time.time()
        print("the func run time  is %s" %(stop_time-start_time))    
    return deco     

@timer
def test2(name):
    print("test2:",name)

test2("alex")
--->
test2: alex
the func run time  is 0.0
1-2-1
# 若是傳入兩個參數呢?
# 要裝飾的函數多是各類各樣的功能
# 因此須要 *args  **kwargs
import time
def timer(func):    
    def deco(*args,**kwargs):
        start_time = time.time()
        func(*args,**kwargs)      
        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(name,age):
    print("test2:",name,age)

test1()
test2("alex",11)
--->
in the test1
the func run time  is 3.0008721351623535
test2: alex 11
the func run time  is 0.0009975433349609375
相關文章
相關標籤/搜索