day11-裝飾器

1.舉例講解

  這裏先導入time模塊的概念。app

import  time
print(time.time()) # 打印距離1970年到如今的秒數
time.sleep(1) # 停留一秒再執行下一句
'''
測試一段代碼執行會通過多長時間
'''
import time
def func(): # 被裝飾的函數
    time.sleep(0.01) # 因爲一個print語句太少,因此這裏故意設置一個時間間隔,以達到預期效果。
    print('今天好熱')

def timmer(f): # 裝飾器函數
    def inner():
        start = time.time()
        f() # 調用被裝飾的函數
        end = time.time()
        print('時間間隔爲:',end - start)
    return inner

result = timmer(func)
result()

  上面一段代碼就是一個簡單的裝飾器。ide

  一般爲了是代碼更加優美,因而引入語法糖的概念。這裏將對上述第二段代碼進行改進,他們的做用和結果徹底相同。函數

'''
測試一段代碼執行會通過多長時間
'''
import time

def timmer(f): # 裝飾器函數
    def inner():
        start = time.time()
        f() # 調用被裝飾的函數
        end = time.time()
        print('時間間隔爲:',end - start)
    return inner

@timmer #語法糖-@裝飾器函數
def func(): # 被裝飾的函數
    time.sleep(0.01) # 因爲一個print語句太少,因此這裏故意設置一個時間間隔,以達到預期效果。
    print('今天好熱')

# result = timmer(func) @timeer與此句一個做用相同
func() # 分析一下,此func等價於timmer(func),也就至關於inner。
'''
測試一段代碼執行會通過多長時間
'''
# 新增功能-裝入帶參數函數的裝飾器
import time

def timmer(f): # 裝飾器函數
    def inner(a):
        start = time.time()
        f(a) # 調用被裝飾的函數
        end = time.time()
        print('時間間隔爲:',end - start)
    return inner

@timmer #語法糖-@裝飾器函數
def func(a): # 被裝飾的函數
    time.sleep(0.01) # 因爲一個print語句太少,因此這裏故意設置一個時間間隔,以達到預期效果。
    print('今天好熱',a)

# result = timmer(func) @timeer與此句一個做用相同
func(1) # 分析一下,此func等價於timmer(func),也就至關於inner。
裝入帶參數函數的裝飾器

  上面一段代碼是裝入一個參數,若是我想在被裝飾函數中加入兩個參數呢?也許你會說,再加入一個變量,那麼三個參數呢?這個時候咱們就要用到前面學過的內容:*args。繼續,若是咱們再加入一個關鍵字參數呢?一樣,咱們要用到**kwargs。下面是代碼:學習

'''
測試一段代碼執行會通過多長時間
'''
# 新增功能-裝入帶參數函數的裝飾器
import time

def timmer(f): # 裝飾器函數
    def inner(*args,**kwargs):
        start = time.time()
        f(*args,**kwargs) # 調用被裝飾的函數
        end = time.time()
        print('時間間隔爲:',end - start)
    return inner

@timmer #語法糖-@裝飾器函數
def func(a,b): # 被裝飾的函數
    time.sleep(0.01) # 因爲一個print語句太少,因此這裏故意設置一個時間間隔,以達到預期效果。
    print('今天好熱',a,b)

# result = timmer(func) @timeer與此句一個做用相同
func(1,b = 3) # 分析一下,此func等價於timmer(func),也就至關於inner。

 

2.裝飾器的做用

  (1)不想修改函數的調用方式,可是還想在原來的函數先後添加功能。測試

  (2)timmer就是一個裝飾器函數,只是對一個函數有一些裝飾做用。spa

3.原則-開放封閉原則

  對擴展是開放的。code

  對修改是封閉的。blog

4.裝飾器進階

4.1._name_、_doc_

# 學習._name_和._doc_,在這裏若是不作任何修改,._name_會輸出inner,由於study和inner等價,可是咱們作出如下修改,就會成功輸出study
from functools import wraps #導入
def wrapper(func):
    @wraps(func)# 加上這句
    def inner(*args,**kwargs):
        print('在被裝飾的函數執行前要作的事')
        ret = func(*args,**kwargs)
        print('在被裝飾的函數執行後要作的事')
        return ret
    return inner

@wrapper
def study(days):
    '''
    這是一個註釋
    :param days:
    :return:
    '''
    print('堅持學習%s天'%days)
    return '加油'

# ret = study(10)
# print(ret)

print(study.__name__)# 輸出
print(study.__doc__)

4.2.多個函數下的裝飾器

# 若多個函數同時用一個裝飾器,通常來講就是在函數上面加一個@裝飾器名,可是咱們有不想用它的時候,若是咱們一個一個去刪除它則會很是的麻煩,下面這種方法將會解決這種問題。
import time
Flag = False

def timmer_out(Flag):
    def timmer(func):
        def inner(*args,**kwargs):
            if Flag:
                start = time.time()
                ret = func(*args,**kwargs)
                end = time.time()
                print(end - start)
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return timmer
@timmer_out(Flag)
def para_fir():
    time.sleep(0.1)
    print('the first')

@timmer_out(Flag)
def para_sec():
    time.sleep(0.1)
    print('the second')

para_fir()
para_sec()
# 思想就是在裝飾器外再加上一層,成爲三層裝飾器,經過判斷Flag爲True仍是False,來執行相應的代碼塊

4.3.多個裝飾器

def wrapper1(func):  # func-->f
    def inner1():
        print('wrapper1 ,before func')
        ret = func()
        print('wrapper1 ,after func')
        return ret
    return inner1

def wrapper2(func): # func = inenr1
    def inner2():
        print('wrapper2 ,before func')
        ret = func()
        print('wrapper2 ,after func')
        return ret
    return inner2


@wrapper2 # f = wrapper2(f) -> wrapper2(inner1) = inner2
@wrapper1 # f = wrapper1(f) = inner1
def f():
    print('in f')
    return '哈哈哈'

print(f()) # f = inner2

# result:
# wrapper2 ,before func
# wrapper1 ,before func
# in f
# wrapper1 ,after func
# wrapper2 ,after func
# 哈哈哈

# 仔細觀察這個結果,首先執行wrapper1,將f傳入wrapper1中,因而wrapper1中的func就是f,最後返回一個inner1。接着再執行wrapper2,可是此時傳入wrapper2中的參數是上一次執行返回過來的inner1,因此wrapper2中的func是inner1,最後返回一個inner2。
# 爲何結果是先有wrapper2,可是其實是先執行wrapper1呢,這是由於裝飾器中的語法糖會找最近的一個被修飾的函數,顯然wrapper1更接近f(),而wrapper2比較遠,因此是先執行wrapper1,再是wrapper2。
相關文章
相關標籤/搜索